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

int pthread_detach(pthread_t thread);

void pthread_exit(void *retval);

线程正常终止的方法:

1、return从线程函数返回。

2、通过调用函数pthread_exit使线程退出

3. 线程可以被同一进程中的其他线程取消。

主线程、子线程调用exit, pthread_exit,互相产生的影响。

1、在主线程中,在main函数中return了或是调用了exit函数,则主线程退出,且整个进程也会终止,

此时进程中的所有线程也将终止。因此要避免main函数过早结束。

2、在主线程中调用pthread_exit,   则仅仅是主线程结束,进程不会结束,进程内的其他线程也不会结束,

知道所有线程结束,进程才会终止。

3、在任何一个线程中调用exit函数都会导致进程结束。进程一旦结束,那么进程中的所有线程都将结束。

为什么要使用pthread_join?

线程终止最重要的问题是资源释放的问题。

线程终止时需要注意线程同步的问题。一般情况下,进程中各个线程的运行是相互独立的,线程的终止不会相互通知,也不会影响其他线程,

终止的线程所占用的资源不会随着线程的结束而归还系统,而是仍为线程所在的进程持有。在Linux中,默认情况下是在一个线程被创建后,

必须使用此函数对创建的线程进行资源回收,但是可以设置Threads attributes来设置当一个线程结束时,直接回收此线程所占用的系统资源,详细资料查看Threads attributes。

函数pthread_join用来等待一个线程的结束,pthread_join的调用者将被挂起并等待thread线程终止。需要注意的是一个线程仅允许一个线程使用pthread_join

等待它结束,并且被等待的线程应该处于可join状态。即非DETACHED状态。DETACHED是指某个线程执行pthread_detach后所处的状态。处于DETACHED状态

的线程无法由pthread_join同步。

一个可pthread_join的线程所占用的资源仅当有线程对其执行了pthread_join后才会释放,因此为了防止内存泄漏,所有线程终止时,要么已经被设置为DETACHED状态

要么使用pthread_join来回收资源。

notice:

一个线程不能被多个线程等待。否则第一个收到信号的线程成功返回。其余调用pthread_join的线程返回错误码

ESRCH  No thread with the ID thread could be found.

示例代码:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h> void* thread_func(void* arg)
{
printf("thread:%lu is running\n", pthread_self());
int rv = ;
pthread_exit((void*)rv);
} int main()
{
pthread_t thid;
int rv; pthread_create(&thid, NULL, thread_func, NULL); printf("main thread begin join\n");
pthread_join(thid, (void*)&rv);
printf("main thread end join\n");
printf("the thread:%lu exit:%d\n", thid, rv); return ;
}

将线程的属性称为detached,则线程退出时会自己清理资源。

void*start_run(void*arg)
{
//dosomework
}
 
intmain()
{
  pthread_t thread_id;
 
  pthread_attr_   tattr;
 
  pthread_attr_init(&attr);
 
  pthread_attr_setdetachstate(&attr,  PTHREAD_CREATE_DETACHED);
 
  pthread_create(&thread_id,  &attr,  start_run,  NULL);
 
  pthread_attr_destroy( &attr );
 
  sleep(5);
 
  exit(0);
}
 
在线程设置为joinable后,可以调用pthread_detach()使之成为detached。但是相反的操作则不可以。还有,如果线程已经调用pthread_join()后,则再调用pthread_detach()则不会有任何效果。

线程可以通过自身执行结束来结束,也可以通过调用pthread_exit()来结束线程的执行。另外,线程甲可以被线程乙被动结束。这个通过调用pthread_cancel()来达到目的。

当然,线程也不是被动的被别人结束。它可以通过设置自身的属性来决定如何结束,线程的被动结束分为两种,一种是异步终结,另外一种是同步终结。异步终结就是当其他线程调用pthread_cancel的时候,

线程就立刻被结束。而同 步终结则不会立刻终结,它会继续运行,直到到达下一个结束点(cancellation point)。当一个线程被按照默认的创建方式创建,那么它的属性是同步终结。

1 线程取消的定义

一般情况下,线程在其主体函数退出的时候会自动终止,但同时也可以因为接收到另一个线程发来的终止(取消)请求而强制终止。

2 线程取消的语义

1. 线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略(当禁止取消时)、或者立即终止(当在取消点 或异步模式下)、或者继续运行至Cancelation-point(取消点,下面将描述),总之由不同的Cancelation状态决定。

2. 线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点再处理(退出),或在异步方式下直接 退出。一个线程处理cancel请求的退出操作相当于pthread_exit(PTHREAD_CANCELED)。当然线程可以通过设置为 PTHREAD_CANCEL_DISABLE来拒绝处理cancel请求,稍后会提及。

3. 线程的取消与线程的工作方式(joinable或detached)无关。

3 取消点

根据POSIX标准,pthread_join()、 pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系 统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),从而达到POSIX标准所要求的目标,即如下代码段:   
pthread_testcancel();   
retcode = read(fd, buffer,length);   
pthread_testcancel();

使用前 须判断线程ID的有效性!即判断并保证:thrd != 0 否则有可能会出现“段错误”的异常!

4 程序设计方面的考虑

1. 如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。

2. 当pthread_cancel()返回时,线程未必已经取消,可能仅仅将请求发送给目标线程,而目标线程目前没有到达取消点,如果要知道线程在何时中止,就需要在取消它之后调用pthread_join()。有一个例外是当线程被detach后,不能这样处理:
a) 当join一个已经detached的线程时,返回EINVAL;
b) 如果join后该线程设置为detached,则detach将不起作用。
因此,如果知道一个线程可能会以分离方式运行,就不需要在pthread_cancel()后调用pthread_join()。

5 与线程取消相关的pthread函数

int pthread_cancel(pthread_t thread) 
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。

int pthread_setcancelstate(int state, int *oldstate) 
设 置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和 PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为 NULL则存入原来的Cancel状态以便恢复。

int pthread_setcanceltype(int type, int *oldtype) 
设 置本线程取消动作的执行时机,type有两种取值:PTHREAD_CANCEL_DEFFERED 和 PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和 立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。

void pthread_testcancel(void) 
检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。

6 检测一个线程是否还活着的pthread函数

int pthread_kill(pthread_t thread, int sig
向指定ID的线程发送sig信号,如果线程的代码内不做任何信号处理,则会按照信号默认的行为影响整个进程。也就是说,如果你给一个线程发送了SIGQUIT,但线程却没有实现signal处理函数,则整个进程退出。
pthread_kill(threadid, SIGKILL)也一样,他会杀死整个进程。
如果要获得正确的行为,就需要在线程内实现signal(SIGKILL,sig_handler)。
所以,如果int sig的参数不是0,那一定要清楚到底要干什么,而且一定要实现线程的信号处理函数,否则,就会影响整个进程。
那么,如果int sig的参数是0呢,这是一个保留信号,一个作用就是用来判断线程是不是还活着。
我们来看一下pthread_kill的返回值:
线程仍然活着:0
线程已不存在:ESRCH
信号不合法:EINVAL

 
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<pthread.h>
#include<time.h> pthread_t tid;
sigset_t set; void myfunc()
{
printf("hello\n:");
} void* mythread(void* p)
{
int signum;
while()
{
sigwait(&set, &signum); if (SIGUSR1 == signum)
{
myfunc();
}
else if (SIGUSR2 == signum)
{
printf("I will sleep 2 seconds and exit\n");
sleep();
break;
}
}
} int main()
{
char tmp;
void *status;
sigemptyset(&set);
sigaddset(&set,SIGUSR1);
sigaddset(&set,SIGUSR2);
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_create(&tid,NULL,mythread,NULL); printf(":");
while()
{
char* p = NULL;
char str[]; scanf("%c",&tmp);
p = gets(str); //printf("get %c\n", tmp);
if('a'==tmp)
{
pthread_kill(tid,SIGUSR1);//发送SIGUSR1,打印字符串。
sleep();
}
else if('q'==tmp)
{
//发出SIGUSR2信号,让线程退出,如果发送SIGKILL,线程将直接退出。
pthread_kill(tid,SIGUSR2);
//等待线程tid执行完毕,这里阻塞。
pthread_join(tid,&status);
printf("finish\n");
break;
}
else
{
printf(":");
} }
return ;
}

pthread_exit pthread_join的更多相关文章

  1. 多线程:pthread_exit,pthread_join,pthread_self

    /*exit_join_id.c*/ #include<pthread.h> #include<stdio.h> void* eji(void* agr) { printf(& ...

  2. 线程正常终止pthread_exit,pthread_join,pthread_kill,pthread_cancel,sigwait,sigaddset

    int pthread_join(pthread_t thread, void **retval); int pthread_detach(pthread_t thread); void pthrea ...

  3. Linux多线程学习总结

    线程是程序中完成一个独立任务的完整执行序列,即一个可调度的实体:进程相当于运行中程序的一种抽象.根据运行环境的调度者的身份,线程可分为内核线程和用户线程.内核线程,在有的系统上称为LWP(Light ...

  4. LINUX多线程(一)(创建和退出)

    1. Linux多线程概述 1.1. 概述 进程是系统中程序执行和资源分配的基本单位.每个进程有自己的数据段.代码段和堆栈段.这就造成进程在进行切换等操作时都需要有比较负责的上下文切换等动作.为了进一 ...

  5. 操作系统学习笔记----进程/线程模型----Coursera课程笔记

    操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...

  6. Pthread:POSIX 多线程程序设计【转】

    转自:http://www.cnblogs.com/mywolrd/archive/2009/02/05/1930707.html#phtread_ref POSIX 多线程程序设计  Blaise ...

  7. [posix]Posix多线程编程

    就不排版了,可以到原作者博客下看 转自:http://www.cnblogs.com/zhangsf/archive/2013/09/09/3309867.html 目录表  摘要 译者序 Pthre ...

  8. Thread and Peocess

    Thread and Peocess pthread_create() 原型: int pthread_create(pthread_t* thread, pthread_attr_t* attr, ...

  9. Linux多线程实例练习 - pthread_exit() 与 pthread_join()

    Linux多线程实例练习 - pthread_exit 与 pthread_join pthread_exit():终止当前线程 void pthread_exit(void* retval); pt ...

随机推荐

  1. Python——连接操作数据库

    1.安装MySQL驱动程序.下载自动安装包,双击安装即可,非常简单. 2.连接MySQL,下面是Python示例代码. import MySQLdbconn=MySQLdb.connect(host= ...

  2. 使border处于边框内

    box-sizing需要指定高度,它在这个高度出现,不会增加额外的高度 .box{box-sizing: border-box;height: 64px;}

  3. mysql数据库的维护,备份和复制

    在数据库运行时维护数据库 执行mysql数据库维护的方法之一就是连接mysql服务器,并告诉它做什么事, 如对myisam数据表进行检查或者修复, 可以使用check table tbname或rep ...

  4. 制作keil5的pack

    [原创出品§转载请注明出处] 出处:http://www.cnblogs.com/libra13179/p/6273415.html 我在这里就交大家怎样制作自己的Pack,(这里是我制作好的http ...

  5. IIS 更新EXE文件

    IIS 更新EXE文件 MIME,add,文件扩展名带不带.都可以,会自动加上.的 文件扩展名:.exe MIME类型:application/octet-stream .ini文件

  6. 5 python 内置类

    1.实例属性和类属性 给实例绑定属性的方法是通过实例变量,或者通过self变量: class Chinese: def __init__(self,name,sex,age): self.name = ...

  7. Java并发测试

    要求:模拟200个设备,尽量瞬间并发量达到200. 思路 第一种:线程池模拟200个线程——wait等待线程数达200——notifyAll唤醒所有线程 第二种:线程池模拟200个线程——阻塞线程—— ...

  8. mysqldump之不老将

    –add-drop-database 每个数据库创建之前添加drop数据库语句.mysqldump -uroot -p –all-databases –add-drop-database –add-d ...

  9. Linux 的伪终端的基本原理 及其在远程登录(SSH,telnet等)中的应用

    本文介绍了linux中伪终端的创建,介绍了终端的回显.行缓存.控制字符等特性,并在此基础上解释和模拟了telnet.SSH开启远程会话的过程. 一.轻量级远程登录 之前制作的一块嵌入式板子,安装了嵌入 ...

  10. Implementing the On Item Checked Event for the TListView Control

    The TListView Delphi control displays a list of items in a fashion similar to how Windows Explorer d ...