线程学习笔记(二)

5.终止线程

线程退出的方式有3种

1.线程体函数执行结束,用 pthread_create() 函数创建一个新线程的时候会执行一个函数,这个函数就是线程体函数,如果该函数执行完毕,那么线程退出,类似于住进程的 main() 函数返回。

2.线程被另一个线程取消。这种方法类似于一个进程被另一个进程调用kill()函数杀死。

3.线程自行退出,类似于线程调用一个 exit() 函数。

Linux系统中使用 pthread_exit(void *rval_ptr) 函数终止线程:

头文件:  #include <pthread.h> 

参数:     void *rval_ptr 是一个指向任意类型的指针,该指针指向的区域储存退出信息。

       功能:    该函数取消一个进程并返回一个指针 *rval_ptr ,该返回值是一个指针,其他线程可以得到该指针,得到该指针指向区域的值。

一个线程的结束信息可以有两种,一种是线程体函数返回的指针所指向的区域,,另一种是 pthread_exit(void *rval_ptr) 函数返回的指针 void *rval_ptr 所指向的区域。第一种方法可以获得线程体函数的返回值,第二种方法得到的是 pthread_exit() 函数设置的返回值。

一个线程运行结束后,结束信息保存在内核中,其他线程可以引用此线程的结束信息。

Linux系统中用函数 pthread_join(pthread_t tid, void **rval_ptr) 函数访问指定线程的结束信息。

头文件:  #include <pthread.h> 

参数:    第一个参数tid为需要取得结束线程的标识符,第二个参数rval_ptr为一个用户定义的指针,它可以用来存储被等待线程的返回值。这里需要注意的是,如果该线程正在运行中, pthread_join() 函数会导致线程阻塞,直到执行的线程结束为止。如果指定线程的线程ID和调用线程不属于同一个进程会出错,这也是线程的一个特点,同一进程下的线程共享资源,通信很简单,但是不同进程下的线程不共享资源,通信就没那么方便。

功能:    该函数取得一个执行完成的进程的退出信息,然后存在一个指针中,该指针指向存储线程返回信息的指针的首地址。

返回值:如果成功得到指定线程的退出信息返回0,失败返回错误号。

示例程序: pthread_exit() 函数和 pthread_join() 函数配合使用

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
/* 第一个线程,线程体函数返回 */
void * tfn1(void * arg)
{
       printf("the first\n");
       return (void *)1;    
}
/* 第二个线程,调用pthread_exit函数退出 */
void * tfn2(void * arg)
{
       printf("the second\n");
       pthread_exit((void *) 3);             
       printf("should not be here\n");
}
/* 第三个线程,休眠5秒钟后退出 */
void *tfn3(void *arg)
{
       printf("the third, sleep 10 secconds\n");
       sleep(5); /* 休眠5秒钟 */
       return NULL;
}
int main(void)
{
       pthread_t tid1, tid2, tid3;
       void * res; /* 指向线程的退出信息指针 */
       int err;
       /* 第一个线程的操作 */
       err = pthread_create(&tid1, NULL, tfn1, NULL); /* 创建第一个线程 */
       if(err != 0){
              printf("can’t create thread %d\n", strerror(err));
              exit(1);    
       }
       err = pthread_join(tid1, &res); /* 得到线程退出信息——tfn1函数的返回值 */
       if(err != 0){
              printf("can‘t join thread %d\n", strerror(err));
              exit(1);    
       }
       printf("result from thd1: %d\n", (unsigned int)(res)); /* 输出提示信息 */
       /* 第二个线程的操作 */
       err = pthread_create(&tid2, NULL, tfn2, NULL); /* 创建第二个线程 */
       if(err != 0){
              printf("can’t create thread %d\n", strerror(err));
              exit(1);    
       }
       err = pthread_join(tid2, &res); /* 得到线程的退出信息——pthread_exit函数
                                                               的参数所设置的值 */
       if(err != 0){
              printf("can’t join thread %d\n", strerror(err));
              exit(1);    
       }
       printf("result from thd2: %d\n", (unsigned int)(res));
       /* 第三个线程的操作 */
       err = pthread_create(&tid3, NULL, tfn3, NULL); /* 创建第三个线程 */
       if(err != 0){
              printf("can’t create thread %d\n", strerror(err));
              exit(1);
       }
       err = pthread_join(tid3, NULL); /* 不关心退出信息,只等待第三个线程退出 */
       if(err != 0){
              printf("can’t join thread %d\n", strerror(err));
              exit(1);
       }
       printf("the third thread has done\n");
       return 0;
}

从上边的程序可以看出,这3个线程是串行的,而线程的特点是并行性高,不符合一般的使用习惯,该程序只是为了演示好 pthread_exit() 函数和 pthread_join() 函数的用法,如果实际应用可以采用下边的编程模式:

pthread_create(……);            //创建第1个线程
pthread_create(……);            //创建第2个线程
pthread_create(……);            //创建第3个线程
pthread_join(tid1, &res);      //得到第1个线程的退出信息
pthread_join(tid2, &res);      //得到第2个线程的退出信息
pthread_join(tid3, &res);      //得到第3个线程的退出信息
时间: 2024-10-26 07:22:14

线程学习笔记(二)的相关文章

Java线程学习笔记(二) 线程的异常捕捉

线程异常的捕捉: 正常的情况下,我们在main()方法里是捕捉不到线程的异常的,例如以下代码: public class ExceptionThread implements Runnable{ @Override public void run() { throw new NullPointerException(); } public static void main(String[] args) { ExecutorService executorService = Executors.n

Spring Batch学习笔记二

此系列博客皆为学习Spring Batch时的一些笔记: Spring Batch的架构 一个Batch Job是指一系列有序的Step的集合,它们作为预定义流程的一部分而被执行: Step代表一个自定义的工作单元,它是Job的主要构件块:每一个Step由三部分组成:ItemReader.ItemProcessor.ItemWriter:这三个部分将执行在每一条被处理的记录上,ItemReader读取每一条记录,然后传递给ItemProcessor处理,最后交给ItemWriter做持久化:It

Android学习笔记二

17. 在ContentProvider中定义的getType()方法是定义URI的内容类型. 18. SQLiteDatabase类中的insert/delete/update/query方法其实也挺好用的,我在EquipmentProvider类中做了实现 19. Android专门有个单元测试项目(Android Test Project),在这个项目中,可以新建一个继承AndroidTestCase类的具体测试类来单元测试某个功能.我新建了一个AndroidTestProject项目,在

Android学习笔记二十之Toast吐司、Notification通知、PopupWindow弹出窗

Android学习笔记二十之Toast吐司.Notification通知.PopupWindow弹出窗 Toast吐司 Toast吐司是我们经常用到的一个控件,Toast是AndroidOS用来显示消息的一种机制,它与Dialog不同,Toast不会获取到焦点,通常显示一段时间之后就会自动消失,下面我们来介绍Toast的几种常用方式: 第一种,默认显示方式,也是最常用的方式: Toast.makeText(MainActivity.this, "这是默认的显示方式", Toast.LE

马哥学习笔记二十六——MySQL主从复制

配置MySQL复制基本步骤: 一.master 1.启用二进制日志 log-bin = master-bin log-bin-index = master-bin.index 2.选择一个惟一server-id server-id = {0-2^32} 3.创建具有复制权限的用户 REPLICATION SLAVE REPLICATION CLIENT 二.slave 1.启用中继日志 relay-log = relay-log relay-log-index = 2.选择一个惟一的server

Boost Thread学习笔记二

除了thread,boost::thread另一个重要组成部分是mutex,以及工作在mutex上的boost::mutex::scoped_lock.condition和barrier,这些都是为实现线程同步提供的. mutexboost提供的mutex有6种:boost::mutexboost::try_mutexboost::timed_mutexboost::recursive_mutexboost::recursive_try_mutexboost::recursive_timed_m

Java线程学习笔记(一)

一.线程的创建方式: 老掉牙的话题了,继承 java.lang.Thread父类或者实现Runnalbe接口,这里就提一句: class Thread implements Runnable Thread也是继承了Runnable接口的,Runnable才是大哥. 重写run(),run()里放的都是具体的业务,包括对线程的具体操作. class Thread1 implements Runnable { int i; Thread1(int i) { this.i = i; } @Overri

Caliburn.Micro学习笔记(二)----Actions

Caliburn.Micro学习笔记(二)----Actions 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions,看一下Caliburn.Micro给我们提供了多强大的支持 我们还是从做例子开始 demo的源码下载在文章的最后 例子1.无参数方法调用 点击button把textBox输入的文本弹出来 如果textbox里没有文本button不可点,看一下效果图 看一下前台代码 <Stac

2. 蛤蟆Python脚本学习笔记二基本命令畅玩

2. 蛤蟆Python脚本学习笔记二基本命令畅玩 本篇名言:"成功源于发现细节,没有细节就没有机遇,留心细节意味着创造机遇.一件司空见惯的小事或许就可能是打开机遇宝库的钥匙!" 下班回家,咱先来看下一些常用的基本命令. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/48092873 1.  数字和表达式 看下图1一就能说明很多问题: 加法,整除,浮点除,取模,幂乘方等.是不是很直接也很粗暴. 关于上限,蛤蟆不太清楚

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己