多线程以及pthread线程库的使用

一.什么是线程

        线程是 CPU 调度的最小执行单位,你可以创建一个线程用于 ListenMusic,再创建一个线程去 PlayGame,这样操作系统就是同时处理这两个任务的(并发)。

二.pthread库

(1) 使用说明

        POSIX 标准定义了一套线程操作相关的函数,用于让程序员更加方便地操作管理线程,函数名都是以前缀 pthread_ 开始,使用时要包含 ,而且在链接的时候要手动链接 pthread 这个库,如:gcc main.c -lpthread -o main。 

 

(2) 常用函数

1. pthread_create

函数原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

功能说明:创建一个线程。

参数说明

thread:线程句柄,需要先定义一个 pthread_t 类型变量 thread,将该变量的地址 &thread 传递到该参数中去。这是一个传出参数,传递进去的 thread 会得到系统为我们创建好的线程句柄。

attr:线程属性,通过该参数可以设置创建的线程属性,如果要使用默认属性直接传递 NULL 即可。

start_routine:线程函数,它是一个函数指针类型,返回类型为 void *,参数为一个 void * 类型变量,创建好这样类型的一个函数,将函数名传递进去即可。

arg:线程参数,代表需要在主线程传递给子线程的参数,给 arg 赋值后可以在线程函数的参数中取到。

返回值说明

        成功情况下返回 0,失败情况下返回错误码,并且 tid 的值是不确定的。Linux 环境下所有线程函数调用失败时均是返回错误码,除了部分返回值为 void 的函数。关于错误码的说明在这里的第 8 小节。

 

2. pthread_self

函数原型:pthread_t pthread_self(void);

功能说明:获取线程 ID。

参数说明:无参数。

返回值说明:如果在主线程中调用该函数会返回主线程的线程 ID,如果在子线程中调用该函数会返回子线程的线程 ID,该函数没有失败的情况。

额外说明:线程 ID 是进程内部识别标志,两个进程间线程 ID 允许相同。

 

3. pthread_equal

函数原型:int pthread_equal(pthread_t t1, pthread_t t2);

功能说明:比较两个线程 ID 是否相等,在 Linux 系统中 pthread_t 都设计为 unsigned long 类型,所以可以直接用 == 判别是否相等,但是如果某些系统设计为结构体类型,那么就可以通过 pthread_equal 函数判别是否相等了。

参数说明:要比较的两个线程 ID。

返回值说明:若相等返回非 0 数值,否则返回 0。

 

4. pthread_exit

函数原型:void pthread_exit(void *retval);

功能说明:将单个线程退出。

参数说明:retval 为该线程的返回状态,如果主线程调用 pthread_join 可以获取到该返回状态。

返回值说明:void。

额外说明:如果在主线程中调用了 pthread_exit(NULL),则主线程退出,如果子线程存在会继续执行。如下代码,就算主线程先退出了,也不会影响子线程打印"我是子线程"。注意如果使用 exit 退出会导致整个进程结束。

多线程以及pthread线程库的使用_第1张图片

 

5. pthread_join

函数原型:int pthread_join(pthread_t thread,void **retval);

功能说明:阻塞等待线程退出,获取线程退出状态,相当于进程中的 waitpid 函数,如果线程退出,pthread_join 立刻返回。

参数说明

thread:代表要等待线程的线程 ID

retval:获取该线程的退出状态

返回值说明

        成功情况下返回 0,失败则返回错误码。

多线程以及pthread线程库的使用_第2张图片

6. pthread_detach

函数原型:int pthread_detach(pthread_t thread);

功能说明:将线程 ID 为 thread 的线程分离出去,所谓分离出去就是指主线程不需要再通过 pthread_join 等方式等待该线程的结束并回收其线程控制块(TCB)的资源,被分离的线程结束后由操作系统负责其资源的回收。

参数说明:thread 为要分离的线程的线程 ID。

返回值说明

        成功情况下返回 0,失败情况下返回错误码。

额外说明

        一般来说,主线程是要负责创建出来的子线程的资源回收工作的。如果主线程先于子线程退出并且子线程没有设置为分离状态,那么子线程结束后其资源是无法得到回收的,会造成资源浪费和系统臃肿;如果主线程先于子线程退出但是子线程时分离状态,那么子线程退出的时候操作系统会自动回收其资源。

 

7. pthread_cancel

函数原型:int pthread_cancel(pthread_t thread);

功能说明:杀死线程。

参数说明:thread 为要杀死的线程的线程 ID。

返回值说明:成功情况下返回 0,失败情况下返回错误码。

多线程以及pthread线程库的使用_第3张图片

多线程以及pthread线程库的使用_第4张图片

程序说明

        分别创建了两个线程,pthread_func3 是一个死循环。在主线程中 sleep(3) 之后调用 pthread_cancel 结束子线程 pthread_func3,再调用 pthread_join 回收该子线程,由于子线程已经被杀死,此时 pthread_join 返回 -1。

        如果在子线程中的 while(1) 里,将 printf 和 sleep 函数注释掉,会发现杀不死该线程,原因是 pthread_cancel 并不等待线程终止,它仅仅提出了一种请求,需要子线程执行到特定的取消点才能终止该线程(如一些系统调用 write,pause 等地方)。如果线程中没有系统调用的函数,可以加入 pthread_testcancel 函数作为取消点。

 

8. 常见错误码

EDEADLK:检测到线程发生死锁

EINVAL:线程不是可以等待回收的线程(后续会讲到线程分离)或者有其他线程已经准备等待回收该线程了

ESRCH:该线程 ID 不存在

 

三.使用线程的好处

        在 Linux 编程中,多线程编程无疑是十分重要的。它可以提高程序的并发处理能力,线程间通信和共享数据十分方便,而且相对于多进程来说,它更加轻量级、好用。

你可能感兴趣的:(多线程多进程,C++多线程)