Linux线程基本操作
2022-02-25 # 学习笔记 # Linux

Linux线程

基本操作

查看线程id:

1
pthread_t pthread_self(void); 

返回值为线程 id。 线程 id 是在进程地址空间内部,用来标识线程身份的 id 号。

注意:线程id不同于我们在使用ps -Lf命令是所看到的LWP值,LWP可理解为线程号,与进程pid的命名格式相同,创建线程时的LWP也会顺着PID向下排列。

线程的创建

1
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*start_rountn)(void *), void *arg);

参数:

  • 参 1:传出参数,表新创建的子线程 id

  • 参 2:线程属性。传 NULL 表使用默认属性。(线程属性相关的操作补充于后面)

  • 参 3:子线程回调函数。创建成功,ptherad_create 函数返回时,该函数会被自动调用。

  • 参 4:参 3 的参数。没有的话,传 NULL

返回值:

  • 成功:0

  • 失败:errno

注意:如果主线程先于子线程结束,那么子线程也会随之结束。而并不会像我们在处理进程时所看到的子进程会继续执行完成的情况。这是因为主线程结束意味着main函数的返回。那么整个进程也会随之结束。

解决方式:可以用下面的线程回收机制,也可以采用线程分离,将子进程分离,由操作系统来负责回收。

线程的退出和关闭

自行退出

1
void pthread_exit(void *retval);

退出当前线程。

retval:返回值。 无返回值时,填NULL。

这里的返回值可以理解为线程函数的返回值。可以被其他线程通过回收的方式获取到。

概念区分:

pthread_exit()用于线程退出,可以指定返回值,以便其他线程通过pthread_join()函数获取该线程的返回值

return,是函数返回到调用者,不一定是线程函数。只有线程函数return,线程才会退出

exit()是进程退出,调用时会使整个进程退出。因此退出线程不能使用exit。

其他线程控制退出

1
int pthread_cancel(pthread_t thread);

杀死一个线程。

参数:thread: 待杀死的线程 id

返回值:成功:0 失败:errno

被杀死的线程的返回值为-1,可以使用pthead_join回收。

注意:通过这一函数杀死进程的优先级比较低。只有当要被杀死的线程进入内核才能够被杀死。如果要被杀死的线程一直在用户态进行运算,那么这一函数便不会起作用。除了通过类似于printf一类函数使其进入内核态,还可以使用另一个函数。

1
pthread_testcancel();

只需要让可能被杀死的函数周期性的调用这一函数,来检测一下是否有被杀死的消息即可。

线程的回收

1
int pthread_join(pthread_t thread, void **retval);

阻塞 回收线程,与waitpid类似。

thread: 待回收的线程id

retval:传出参数,被回收的线程的返回值。

返回值:成功:0 失败:errno

线程的分离

通过函数设置

设置线程分离

1
int pthread_detach(pthread_t thread); 

thread: 待分离的线程 id
返回值:成功:0 失败:errno

分离后的线程将由系统自动负责回收,而不需要手动回收。

通过线程属性设置

线程属性操作:线程属性为一个结构体。内部结构被封装。可以通过调用这些接口来操作线程属性。然后在创建线程的时候传入被设置好的线程属性即可。这样创建出来的进程在被创建好的时候就是分离态。

1
2
3
4
5
pthread_attr_t attr; //创建一个线程属性结构体变量
pthread_attr_init(&attr);//初始化线程属性
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//设置线程属性为分离态
pthread_create(&tid, &attr, tfn, NULL); //借助修改后的设置线程属性创建为分离态的新线程
pthread_attr_destroy(&attr); //销毁线程属性

问:线程分离后,其原本的进程结束了。分离后的线程还会继续执行吗?

答:不会继续执行

测试代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h> 
#include <unistd.h>
#include <pthread.h>


void* childFunc(void* arg)
{
int i = 0;
while (i < 5) {
printf("I'm alive\n");
sleep(1);
i++;
}
return NULL;
}


int main(int argc, char* argv[])
{
pthread_t tid;
pthread_create(&tid, NULL, childFunc, NULL);
pthread_detach(tid);
sleep(2);
return 0;
}

从测试结果可以看出,分离出的线程在主进程结束之后也会随之结束。

线程和进程控制原语比对

线程控制原语 进程控制原语
pthread_create() fork();
pthread_self() getpid();
pthread_exit() exit();
pthread_join() wait()/waitpid()
pthread_cancel() kill()
pthread_detach()