使用pthread线程库中的接口就可以实现Linux系统下的多线程;
makefile:
mythread:mythread.cpp
g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
rm -f mythread
-lpthread参数的作用是引入线程库;
因为多线程的创建方法是库提供的,所以必须引入该库;
如果编译时不加-lpthread:
mythread.cpp
#include
#include
#include
#include
#include
using namespace std;
//pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void* threadRun(void* args)
{
const string name = (char*)args;
while(true)
{
cout << name << ", pid: " << getpid() << "\n" << endl;
sleep(1);
}
}
int main()
{
pthread_t tid[5];
char name[64];
for(int i = 0; i < 5; i++)
{
snprintf(name, sizeof(name), "%s-%d", "thread", i);
pthread_create(tid+i, nullptr, threadRun, (void*)name);
sleep(1);//缓解传参的bug
}
while(true)
{
cout << "main thread, pid: " << getpid() << endl;
sleep(3);
}
return 0;
}
上述代码在一个进程内创建了5个线程,每个线程都运行了threadRun函数,打印出他们的PID;
运行结果:
这些线程的pid都是一样的,证明线程在进程内部运行;
在用户层面上看到的只是一个进程;
可以使用ps -aL代码产看线程,-L就是查看轻量级进程的选项;
LWP是轻量级进程PID,这些是不一样的,第一个PID和LWP是一样的,就叫做主线程;
OS调度的时候,看的是LWP;
所有的线程都是使用进程的资源,一旦进程退出,所有线程都退出;
进程的多个线程共享同一地址空间,如果定义一个函数,各线程都可以调用;如果定义一个全局变量,各线程都可以访问;除此之外,各线程还共享以下资源和环境:
文件描述符;
每种信号的处理方式;
当前工作目录;
用户id和组id;
线程共享进程数据,但也拥有自己的一部分数据:
线程ID;
一组寄存器;
栈;
errno;
信号屏蔽字;
调度优先级;
(其中,栈和寄存器代表着线程的动态属性,寄存器就是线程的山下文)
fork创建多进程,底层调用的就是clone函数;
创建多线程底层也需要调用clone函数;
当一个线程触发除0错误时:
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
int a = 10;
a /= 0;
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
while (true)
{
cout << "main thread: " << " running ..." << endl;
sleep(1);
}
return 0;
}
线程在创建并执行的时候,主线程也是需要等待的,如果主线程不等待,就会引发类似于进程的僵尸问题,导致内存泄漏;
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
int i = 0;
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
if(i++ == 3)
break;
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
pthread_join(tid, nullptr);//默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
// while (true)
// {
// cout << "main thread: " << " running ..." << endl;
// sleep(1);
// }
return 0;
}
上面的代码,新线程运行完threadRoutine函数就会退出,而主线程pthread_join会默认阻塞等待新线程退出,然后回回收新线程资源;
监控脚本:
while :; do ps -aL | head -1 && ps -L | grep mythread; sleep 1; done
pthread_join的第二个参数是void**类型,是用来拿到线程执行结果的;
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
int i = 0;
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
if(i++ == 3)
break;
}
cout << "new thread quit" << endl;
return (void*)10;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
void* ret = nullptr;
pthread_join(tid, &ret);//默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
cout << "ret: " << (long long)ret << endl;
return 0;
}
在上面代码中:
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
int i = 0;
int* data = new int[3];//新线程申请空间
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
data[i] = i;
if(i++ == 3)
break;
}
cout << "new thread quit" << endl;
return (void*)data;//返回空间的地址
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
int* ret = nullptr;
pthread_join(tid, (void**)&ret);//默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
for(int i = 0; i < 3; i++)
{
cout << ret[i] << endl;
}
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
int i = 0;
int* data = new int[3];//新线程申请空间
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
data[i] = i;
if(i++ == 3)
break;
}
exit(10);
cout << "new thread quit" << endl;
return (void*)data;//返回空间的地址
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
int* ret = nullptr;
pthread_join(tid, (void**)&ret);//默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
for(int i = 0; i < 3; i++)
{
cout << ret[i] << endl;
}
return 0;
}
运行结果:
可以看出,新线程调用了exit函数退出后,后面的代码都不运行了;
线程内部调用exit,整个进程都会退出;
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
int i = 0;
int* data = new int[3];//新线程申请空间
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
data[i] = i;
if(i++ == 3)
break;
}
cout << "new thread quit" << endl;
pthread_exit((void*)11);//退出码是11
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
int* ret = nullptr;
pthread_join(tid, (void**)&ret);//默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
cout << "ret: " << (long long)ret << endl;
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << endl;
sleep(1);
}
cout << "new thread quit" << endl;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
int count = 0;
while (true)
{
cout << "main thread: "
<< " running ..." << endl;
sleep(1);
count++;
if (count == 5)
break;
}
pthread_cancel(tid);
cout << "pthread cancle: " << tid << endl;
int *ret = nullptr;
pthread_join(tid, (void **)&ret); // 默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
sleep(5);
return 0;
}
上面的代码:新线程一直运行,由主线程取消新线程;
运行结果:
打印出线程id:
与LWP是不同的:
因为线程id的本质是一个地址;
我们目前使用的不是Linux自带的创建线程的接口,我们用的是pthread库中的接口;
线程运行需要有独立的栈区,保证栈区是每一个线程独占的方法是:由用户层提供栈区;
新线程的栈区底层就是用clone函数实现的,child_stack参数就是栈区的地址;
线程可以自己获取自己的id:
#include
#include
#include
#include
#include
using namespace std;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
while (true)
{
cout << "new thread: " << (char *)args << " running ..." << pthread_self() << endl;
sleep(1);
}
cout << "new thread quit" << endl;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
while (true)
{
cout << "main thread: "
<< " running ..." << endl;
sleep(1);
}
int *ret = nullptr;
pthread_join(tid, (void **)&ret); // 默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit\n ";
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
int g_val = 0;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
while (true)
{
cout << (char *)args << " : " << g_val << &g_val << endl;
sleep(1);
g_val++;
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
while (true)
{
cout << "main thread: " << " : " << g_val << &g_val << endl;
sleep(1);
}
return 0;
}
上面的代码创建了一个全局变量,由主线程和新线程同时访问:
可以看到,所有进程是共享全局变量的;
如果在线程的内部调用函数替换:
#include
#include
#include
#include
#include
using namespace std;
__thread int g_val = 0;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
sleep(5);
execl("/bin/ls", "ls");
while (true)
{
cout << (char *)args << " : " << g_val << " &: " << &g_val << endl;
sleep(1);
g_val++;
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
while (true)
{
cout << "main thread: " << " : " << g_val << " &: "<< &g_val << endl;
sleep(1);
//count++;
// if (count == 5)
// break;
}
return 0;
}
运行结果:
在线程内部进行程序替换,会导致整个进程都被替换,整个进程直接执行替换的程序;
#include
#include
#include
#include
#include
#include
#include
using namespace std;
__thread int g_val = 0;
// pthread函数的回调函数参数,传的是返回值是void*的函数指针,函数的参数也是void*
void *threadRoutine(void *args)
{
pthread_detach(pthread_self());
while (true)
{
cout << (char *)args << " : " << g_val << " &: " << &g_val << endl;
sleep(1);
g_val++;
// data[i] = i;
// if(i++ == 3)
break;
}
pthread_exit((void*)11);//退出码是11
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");
while (true)
{
cout << "main thread: " << " : " << g_val << " &: "<< &g_val << endl;
sleep(1);
break;
}
int n = pthread_join(tid, nullptr);
cout << "errstring: " << strerror(n) << endl;
return 0;
}
这样会报错:
加上pthread库的编译选项:
就可以运行了:
因为语言级别的线程库底层使用的是原生线程库,都是对原生线程库的封装;