目录
对页表的再次理解(以32位为例)
线程在进程内部执行,是os调度的基本单位。
如何理解线程?
-------------------
上图中,每一个task_struct就是一个线程,红色方框内是属于一个进程。
创建线程,不用构建新的进程地址空间,页表,所以创建线程比创建进程更轻量化。
创建线程,只需要利用主线程(原进程)的地址空间,页表等资源。
在cpu看来,并不关心执行流是进程还是线程,只认task_struct,此时,可以说linux没有真正意义上的线程结构,是用进程task_struct模拟线程的,linux下的进程,统称为:轻量级进程!!!
-----------------------------------------------------------------------------------------------------------------------------
如何理解进程?
--------------------
用户视角:内核数据结构+对应的代码和数据!
内核视角:承担分配系统资源的实体!
----------------------------------------------------------------------------------------------------------------------------
线程的优点
线程的缺点
线程异常
因为创建的新线程,与主线程共用地址空间,页表等,所以新线程出现异常就会引起整个线程组异常。
线程用途
进程vs线程
关于主线程和新线程对栈的使用
主线程和子线程用的栈不在同一个区域,主线程用的栈就在地址空间的栈区,但是新线程用的栈区是在pthread库中对应的区域。
那么,怎么区分各个新线程的栈?
void *threadrun(void *args)
{
const string name = (char *)args;
while (true)
{
cout<<pthread_self()<<endl;
sleep(1);
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadrun, (void *)"new thread");
while (true)
{
cout << "main thread, pid: " << getpid() << endl;
sleep(1);
}
}
输出结果:
我们发现,新线程的id值非常大,我们在哪里见到过这么大的值那?--------虚拟地址!!!
其实不然,新线程的id值,就是用来标识该线程在pthread库中对应的存储信息的起始位置,可以结合前边的图看到。
主线程与新线程共用全局变量
void *threadroutine(void *args)
{
pthread_detach(pthread_self());
while(true)
{
cout << (char*)args << " : " << g_val << " &: " << &g_val << endl;
g_val++;
sleep(1);
}
pthread_exit((void*)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);
}
return 0;
}
部分打印结果: (我们发现,新线程修改全局变量,主线程的也会改变,而且地址是一样的!)
如果用 __thread 来修饰全局变量的话,会发现新线程修改全局变量,主线程看到的值并不会发生改变,而且二者对应的地址不同。
进程id和线程id
认识进程id和线程id
void *threadrun(void *args)
{
const string name = (char *)args;
while (true)
{}
}
int main()
{
pthread_t tid[5];
for (int i = 0; i < 5; i++)
{
pthread_create(tid + i, nullptr, threadrun, (void *)"");
}
while (true)
{}
}
其中,pid值和lwp值相同的是主线程,其余的都是新线程。
线程控制
posix线程库
创建线程
线程终止
pthread_exit函数
pthread_cancel函数
线程等待
为什么需要线程等待?
分离线程
关于新线程退出结果
void *threadroutine(void *args)
{
while(true)
{
pthread_testcancel();
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, nullptr, threadroutine, (void *)"thread 1");
int count = 0;
while (true)
{
count++;
if (count >= 5)
break;
}
int n= pthread_cancel(tid);
cout <<n<<endl;
cout << "pthread cancel: " << tid << endl;
int *ret = nullptr;
pthread_join(tid, (void **)&ret); // 默认会阻塞等待新线程退出
cout << "main thread wait done ... main quit ...: new thead quit : " << (long long)ret << "\n";
return 0;
}
如果调用pthread_cancel来终止线程,则线程的退出码是 -1。
当然,如果新线程指定返回退出结果,可通过(void*)进行强转,然后主线程再(long long)进行强转,就可获得。
发表评论