Linux下的多线程编程
线程是操作系统能够进行调度运算的最小单位,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程可以并发多个线程,每条线程执行不同的任务。
线程的创建
#include <pthread.h>
int pthread_create(pthread_t *pthread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
-
pthread: 由pthread_create在线程创建成功后返回的线程句柄,该句柄在后续操作线程中用于标志该新建的线程,pthread_t是unsigned long int类型的变量,用来表示线程的ID,输出参数;
-
attr: 输入参数,指定新建线程的属性,如线程栈的大小等;如果值为NULL表示使用系统默认属性;
-
arg:输入参数,传递给新线程入口函数的参数;
-
start_routine: 输入参数,新建线程的入口函数;
-
函数成功,返回0;失败则返回相关错误码。
主线程,这是一个进程的初试线程,其入口函数为main函数。
在新线程被创建后,便有了一个在其所在进程内(线程依附于进程而存在)唯一的标识符,由pthread_t
表示,成为线程ID。一个线程可以通过调用以下接口获取其ID:
#include <pthread.h>
pthread_t pthread_self(void);
判断两个线程ID的大小是没有意义的,但有时可能需要判断两个给定的线程ID是否相等,使用如下接口:
/*
pthread_equal,若指定的线程ID相同,返回非零值;否则返回0
*/
#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
从系统实现的角度观察线程的创建
创建一个新的线程,从系统实现的角度看,就是创建了一个可调度实体;同一个进程内的线程,共享绝大部分进程的资源,只有少部分的信息是线程所特有的,如栈和线程特有数据等
假设一个进程内存在4个线程时,内存资源的分配情况:
![进程内存分布](https://i-blog.csdnimg.cn/blog_migrate/b9a81953a46539a9a4b0f42cc1fc700c.png)
可以看出,同一进程内的线程间除了栈是特有的之外,其他内存资源几乎是共享的,多个线程可以同时修改某一内存区,且该修改对同一进程的所有线程都是可见的。
线程的终止
终止某一个线程而不终止整个进程,有三种方法:
- 从线程主函数return,这种方法对主控线程不适用,从main函数return相当于调用exit;
- 一个线程可以调用
pthread_cancel
终止同一个进程中的另一个线程; - 线程可以调用
pthread_exit
终止自己。
一般情况下,线程终止后,其终止状态一直保留到其他线程调用pthread_join
获取它的状态为止。
#include <pthread.h>
int pthread_cancel(pthread_t thread);
杀死(取消)线程,起作用对应进程中的kill()
函数,成功返回0;失败返回错误号。注意:线程的取消并不是实时的,而有一定的延时,需要等待线程到达某个取消点。当一个已经被取消的线程使用pthread_join回收时,得到的返回值为-1.
线程终止函数:
#include <pthread.h>
void pthread_exit(void *retval);
线程的连接
一个线程的终止对于另外一个线程而言是一种**异步的事件,有时我们想等待某个ID的线程终止了再去执行某些操作,pthread_join
函数提供了这种功能:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
参数说明:
-
thread: 输入参数,指定希望等待的线程;
-
retval: 输出参数,等待的线程终止时的返回值,就是在线程入口函数中return的值或者调用pthread_exit函数的参数;
-
成功时返回0,错误返回错误码。
当线程X等待线程Y时,如果线程Y仍在运行,则线程X会阻塞知道线程Y终止;如果线程Y在连接之前已经终止了,那么线程X的连接调用会立即返回。
连接线程其实还有另外一层意义,一个线程终止后,如果没有人对它进行连接,那么该终止线程占用的资源,系统将无法回收,而该终止线程将成为僵尸线程。因此,当我们去连接某个线程时,其实也是告诉系统该终止线程的资源可以回收了。
线程的分离
有时我们并不在乎某个线程是不是已经终止了,只希望线程终止后,系统能自动回收该终止线程所占用的资源,pthread_detach
函数为我们提供了这个功能,
#include <pthread.h>
int pthread_detach(pthread_t thread);
该函数参数指定希望执行分离操作的线程,成功返回0,错误返回错误码。
默认情况下,一个线程终止后,是需要在被连接后系统才能回收其占有的资源的。如果调用上述函数,则线程终止后系统将自动回收其资源。