线程控制原语小结

在本篇博客中主要总结一下linux下,线程的一些控制原语。
  在Linux环境下,所有线程特点,失败均直接返回错误号。所以我们可以利用strerror()将错误信号所代表的具体错误打印出来。参数为发生错误所返回的错误信号。例如:
  

ret = pthread_create(&tid ,NULL ,thrd_func ,NULL);
if(ret != 0)
{
    fprintf(stderr , "pthread_create error : %s \n", strerror(ret));
    exit(1);
}

1、pthread_create()函数

作用

  创建一个新线程。 其作用,对应进程中fork() 函数。

原形

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

返回值

  返回值:成功:0; 失败:错误号 (Linux环境下,所有线程特点,失败均直接返回错误号)。

说明

  参数1:传出参数,保存系统为我们分配好的线程ID
  参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
  参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
  参数4:线程主函数执行期间所使用的参数。

注意

  (1)、在一个线程中调用pthread_create()创建新的线程后,当前线程从pthread_create()返回继续往下执行,而新的线程所执行的代码由我们传给pthread_create的回调函数start_routine决定。start_routine返回时,这个线程就退出了。
  (2)、pthread_create成功返回后,新创建的线程的id被填写到thread参数所指向的内存单元。线程id的类型是thread_t,它只在当前进程中保证是唯一的,在不同的系统中thread_t这个类型有不同的实现,它可能是一个整数值,也可能是一个结构体,也可能是一个地址,所以不能简单地当成整数用printf打印,调用pthread_self()可以获得当前线程的id。

2、pthread_self()函数

作用

  获取当前线程ID。其作用对应进程中 getpid() 函数。

原形

pthread_t pthread_self(void); 

返回值

  成功:返回线程ID;    失败:错误号;

说明

  线程ID:pthread_t类型,本质:在Linux下为无符号整数(%lu),其他系统中可能是结构体实现;线程ID是进程内部,识别标志。(两个进程间,线程ID允许相同)。

注意

  不应使用全局变量 pthread_t tid,在子线程中通过pthread_create传出参数来获取线程ID,而应使用pthread_self。

3、pthread_exit()函数

作用

  将单个线程退出

原形

void pthread_exit(void *retval)

返回值

  成功:0;    失败:无;

说明

  retval表示线程退出状态,通常传NULL。

注意

  (1)、线程中,禁止使用exit函数,会导致进程内所有线程全部退出。 
  (2)、pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。

4、pthread_join()函数

作用

  线程退出,获取线程退出状态 其作用,对应进程中 waitpid() 函数。

原形

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

返回值

  成功:0;失败:错误号

说明

  thread:线程ID (不是指针);
  retval:存储线程结束状态。

参数retval非空用法

  (1)、调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
  1、如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
  2、如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
  3、如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
  4、如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

5、pthread_detach()函数

作用

  实现线程分离。

原形

int pthread_detach(pthread_t thread);  

返回值

  成功:0;失败:错误号

说明

  线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后,其退出状态不由其他线程获取,而直接自己自动释放。网络、多线程服务器常用。
  进程若有该机制,将不会产生僵尸进程。僵尸进程的产生主要由于进程死后,大部分资源被释放,一点残留资源仍存于系统中,导致内核认为该进程仍存在。

注意

  一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态,这样的线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL错误。也就是说,如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。

6、pthread_cancel()函数

作用

  杀死(取消)线程。其作用,对应进程中 kill() 函数。

原形

int pthread_cancel(pthread_t thread);     

返回值

  成功:0;失败:错误号

注意

  (1)、线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。
取消点:是线程检查是否被取消,并按请求进行动作的一个位置。通常是一些系统调用creat,open,pause,close,read,write等等。(执行命令man 7 pthreads可以查看具备这些取消点的系统调用列表。也可参阅 APUE.12.7 取消选项小节。)
  可粗略认为一个系统调用(进入内核)即为一个取消点。如线程中没有取消点,可以通过调用pthreestcancel函数自行设置一个取消点。
  (2)、被取消的线程, 退出值定义在Linux的pthread库中。常数PTHREAD_CANCELED的值是-1。可在头文件pthread.h中找到它的定义:#define PTHREAD_CANCELED ((void *) -1)。因此当我们对一个已经被取消的线程使用pthread_join()回收时,得到的返回值为-1。

7、线程使用注意事项

  1.主线程退出其他线程不退出,主线程应调用pthread_exit
  2.避免僵尸线程
    ①、pthread_join()
    ②、pthread_detach()
    ③、pthread_create指定分离属性
  被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;
  3.malloc和mmap申请的内存可以被其他线程释放
  4.应避免在多线程模型中调用fork除非,马上exec,子进程中只有调用fork的线程存在,其他线程在子进程中均pthread_exit
  5.信号的复杂语义很难和多线程共存,应避免在多线程引入信号机制。
  6、在编译链接加 -pthread ,因为线程库属于第三方库,gcc默认加载标准库。

猜你喜欢

转载自blog.csdn.net/z_ryan/article/details/79632385
今日推荐