Linux本质上是用轻量级的进程去模拟线程,所以线程并不存在对应的数据结构,只有创建和控制进程的系统调用,所以后来的系统工程师将这些进程的系统调用打包成了第三方库pthread,所以实际在创建线程时,我们需要动态链接到第三方库
目录
一、线程创建函数pthread_create
(1) 参数解析
第一个参数是线程ID,是一个输出型参数,数据类型可看作是一个无符号整型,本质上是地址空间中的一个地址
第二个参数是线程属性,比如设置栈的大小、线程优先级等待,一般设置为NULL,即表示全权交由OS来决定
第三个参数是要线程执行进程中的哪一部分代码,一般写函数的地址,属于回调函数,函数的返回值是void*,参数类型也是void*
第四个参数是要给回调函数传递的参数
(2) 返回值
创建成功返回0,创建失败返回一个错误码
二、创建一个新线程
一个进程被创建的时候,至少有一个PCB,所以至少存在一个线程,创建新的线程以后,站在CPU的角度,其实没有多大变化,无非就是运行队列里多了一个PCB,一个PCB的运行时间片到了,就轮到下一个PCB,只不过在我们看来就相当于在同时运行
核心代码和Makefile文件的代码如下
测试结果如下,我们发现主线程和子进程同属于一个进程
那我要怎么知道是不同的线程呢??方式有两种
=======================方式一:命令行指令查看=======================
第一种方式重新运行执行文件,然后新开一个窗口,在命令行输入
ps -aL #-L查看轻量级进程
LWP:Light Weight Process(轻量级进程)
我们会发现PID是一样的,但是LWP是不同的,这就证明我们的子线程创建成功了,此时依旧是一个进程,但是有两个执行流
=======================方式二:使用pthread_self()查看=======================
使用这个函数的话,我们需要稍微修改一下原来的代码
测试结果如下:
三、一次创建多个新线程
创建一个线程时,我们传入的是tid的地址,现在要创建多个线程,我们可以先创建一个数组tid[5],然后传递数组每个元素的地址 tid + i。我们在线程中打印一下创建好的线程ID
ps:为了支持常用的for循环写法,最好在Makefile中添加 -std = c99
测试结果如下,虽然执行的顺序不一样,可能和CPU的调度顺序有关系,但是总的来说,5个线程都被创建出来了
四、线程的弱健壮性验证
当一个线程崩溃的时候,OS会给进程发送信号来中止异常的根源,这个时候,进程就会崩溃,从而导致其他线程也崩溃,所以线程的崩溃会影响到其他线程,也会影响到整个进程
下面我们在第3个线程中添加一个1/0的计算来引发进程崩溃
测试结果正如我们所说的,整个进程都会挂掉