第一个参数是所创建进程的pid。
第二个是线程的属性。
第三个参数是返回值为void*,参数也为void*的函数指针。
第四个参数是给第三个参数的参数,也就是给给函数传参。
#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
//新线程
void *ThreadRoutine(void*args)
{
const char*threadname=(const char*)args;
while(true)
{
cout<<"I am a new thread:"<<threadname<<"pid:"<<getpid()<<endl;
sleep(1);
}
}
int main()
{
// 已经有进程了
pthread_t tid;
pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 1");
//主线程
sleep(2);
pthread_t tid1;
pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 2");
sleep(2);
pthread_t tid2;
pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 3");
sleep(2);
pthread_t tid3;
pthread_create(&tid,nullptr,ThreadRoutine,(void*)"thread 4");
while(true)
{
cout<<"I am main thread"<<"pid:"<<getpid()<<endl;
sleep(1);
}
return 0;
}
线程属于同一个进程,所以它们的pid相同。
要区分它们,就需要LWP(Lightweight processes)。
使用ps -aL命令可以查看Linux内部的轻量级进程 。
其中L指的就是light(轻)。
也就是说,在pcb中,除了pid,还有lwp这个字段。
操作系统调度的时候,看的也是lwp,判断是主线程还是新线程,看的是lwp是否等于pid。
线程的本质就是CPU调度的基本代码,Linux内核复用了进程代码,用进程pcb模拟充当线程。
在数据结构层面上,它只创建pcb,和父进程指向同一块地址空间。
在资源划分上,把代码数据划分好,各自私有或者各自执行一部分代码,执行流就可以并发跑了。
线程间大部分资源是共享的,进程要保证独立性,而线程在进程中运行。
线程较进程更轻量化,调度上来说,pcb切换另一个pcb,地址空间,页表等是不用切换的,只需更换进程运行中寄存器产生的临时数据。
换句话说,线程切换时,不需要切换CPU内部的所有寄存器的数据,而只需更换少部分。
这个是线程轻量化的一个原因,但不是主要原因,主要原因是下面这个。
CPU除了寄存器外,还集成了一个比较大的存储空间,就是硬件级别的cache。
cache会对用户操作做出预判,加以缓存,大概率猜对,猜不对也没关系,重新缓存。
预加载是一种IO,但是也不会对整体效率有太大影响。
我们一般把保存在cache中的一部分代码和数据叫做热数据。
cache的缓存是以进程为单位的,线程间切换不需要切换cache。
因为cache缓存的本来就是地址空间中的代码和数据。
进程和线程共享进程的时间片,创建线程时时间片不会增多,因为时间片本身也是资源。