lienhua34
2014-11-08

进程控制三部曲中我们学习了进程的创建、终止以及获取终止状态等的进程控制原语。线程的控制与进程的控制有相似之处,在表 1中我们列出了进程和线程相对应的控制原语。

表 1: 进程原语和线程原语的比较
进程原语 线程原语 描述
fork pthread_create 创建新的控制流
exit pthread_exit 从现有的控制流中退出
waitpid pthread_join 从控制流中得到退出状态
atexit pthread_cleanup_push 注册在退出控制流时调用的函数
getpid pthread_self 获取控制流的 ID
abort pthread_cancel 请求控制流的非正常退出

1 线程

每个线程都有一个线程 ID,线程只在它所属的进程环境中有效。线程ID 使用pthread_t 表示。可以通过调用pthread_self 函数获取线程自身的线程 ID,

#include <pthread.h>

pthread_t pthread_self(void);

返回值:调用线程的线程ID

线程 ID 不一定是一个非负整数,也有可能是一个结构体。所以,要对比两个线程是否相同,必须使用pthread_equal 函数来进行,

#include <pthread.h>

int pthread_equal(pthread_t tid1, pthread_t tid2);

返回值:若相等则返回非0值,否则返回0

2 线程的创建

可以通过调用pthread_create 来创建新的线程,

#include <pthread.h>

int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);

返回值:若成功则返回0,否则返回错误编码

其中,参数 tidp 用于返回成功创建的新线程的线程 ID。参数 attr 用于定制各种不同的线程属性,如果设置为 NULL,表示创建一个默认属性的线程。成功创建的新线程将从参数start_rtn 所指向的函数开始执行,该函数接收一个 void * 的参数 arg,并返回一个 void * 的返回值。

注意:pthread_create 失败的时候返回的是错误编码,表示我们可以通过调用 strerror 函数来获取具体的错误信息。

下面我们来看一个创建新进程的例子,

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h> void *
my_thread(void *arg)
{
printf("in new thread. tid: %u\n", (unsigned int)pthread_self());
return ((void *));
} int
main(void)
{
int err;
pthread_t tid; err = pthread_create(&tid, NULL, my_thread, NULL);
if ( err != ) {
printf("can't create thread: %s\n", strerror(err));
exit(-);
}
printf("in main thread: %u\n", (unsigned int)pthread_self());
sleep();
exit();
}

编译该程序,生成并执行文件pthread_create_demo。从下面的运行结果,我们可以看到在 main 函数和my_thread 函数打印的线程 ID 是不一样的。

lienhua34:demo$ gcc -o pthread_create_demo -pthread pthread_create_demo.c
lienhua34:demo$ ./pthread_create_demo
in main thread:
in new thread. tid:

3 线程终止

如果进程中的任一线程调用了exit、_Exit 或_exit 函数,那么整个进程都将会终止。那如果我们只是想单独的终止一个线程呢?有三种方式,

1. 线程从启动例程中返回,返回值即为线程的退出码。

2. 被同一个进程中的其他线程取消。

3. 线程调用函数pthread_exit。

pthread_exit 函数的声明如下,

#include <pthread.h>

void pthread_exit(void *rval_ptr);

进程中其它线程可以通过调用pthread_join 来获取指定线程的退出码。

#include <pthread.h>

int pthread_join(pthread_t tid, void **rval_ptr);

返回值:若成功则返回0,否则返回错误编号

pthread_join 函数会使调用线程一直阻塞,直到指定的线程终止。如果指定线程只是从它的启动例程中返回,rval_ptr 将包含返回码。如果线程被取消,由rval_ptr 指定的内存单元将被置为PTHREAD_CANCELED。

下面我们来看一个线程终止的例子,

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h> void *
thr_fn1(void *arg)
{
printf("in thread 1\n");
return ((void *));
} void *
thr_fn2(void *arg)
{
printf("in thread 2\n");
pthread_exit((void *));
} int
main(void)
{
int err;
pthread_t tid1, tid2;
void *tret; err = pthread_create(&tid1, NULL, thr_fn1, NULL);
if ( err != ) {
printf("can't create thread 1: %s\n", strerror(err));
exit(-);
} err = pthread_create(&tid2, NULL, thr_fn2, NULL);
if (err != ) {
printf("can't create thread 2: %s\n", strerror(err));
exit(-);
} err = pthread_join(tid1, &tret);
if (err != ) {
printf("can't join with thread 1: %s\n", strerror(err));
exit(-);
}
printf("thread 1 exit code: %d\n", (int)tret); err = pthread_join(tid2, &tret);
if (err != ) {
printf("can't join with thread 2: %s\n", strerror(err));
exit(-);
}
printf("thread 2 exit code: %d\n", (int)tret); exit();
}

pthread_exit_demo.c

编译该程序,生成并执行文件pthread_exit_demo,

lienhua34:demo$ gcc -o pthread_exit_demo -pthread pthread_exit_demo.c
lienhua34:demo$ ./pthread_exit_demo
in thread
in thread
thread exit code:
thread exit code:

(done)

UNIX环境编程学习笔记(26)——多线程编程(一):创建和终止线程的更多相关文章

  1. 孙鑫VC学习笔记:多线程编程

    孙鑫VC学习笔记:多线程编程 SkySeraph Dec 11st 2010  HQU Email:zgzhaobo@gmail.com    QQ:452728574 Latest Modified ...

  2. Python Web学习笔记之多线程编程

    本次给大家介绍Python的多线程编程,标题如下: Python多线程简介 Python多线程之threading模块 Python多线程之Lock线程锁 Python多线程之Python的GIL锁 ...

  3. python基础课程_学习笔记26:编程的乐趣

    编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...

  4. 网络编程学习笔记:Socket编程

    文的主要内容如下: 1.网络中进程之间如何通信? 2.Socket是什么? 3.socket的基本操作 3.1.socket()函数 3.2.bind()函数 3.3.listen().connect ...

  5. python核心编程学习记录之多线程编程

  6. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  7. 多线程编程学习笔记——async和await(二)

    接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...

  8. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记——async和await(一) 接上文 多线程编程学习笔记——async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  9. 多线程编程学习笔记——使用异步IO(一)

    接上文 多线程编程学习笔记——使用并发集合(一) 接上文 多线程编程学习笔记——使用并发集合(二) 接上文 多线程编程学习笔记——使用并发集合(三) 假设以下场景,如果在客户端运行程序,最的事情之一是 ...

  10. 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端

    接上文 多线程编程学习笔记——使用异步IO 二.   编写一个异步的HTTP服务器和客户端 本节展示了如何编写一个简单的异步HTTP服务器. 1.程序代码如下. using System; using ...

随机推荐

  1. 基于jQuery功能非常强大的图片裁剪插件

    今天我们要来介绍一款基于jQuery功能非常强大的图片裁剪插件,这款jQuery图片裁剪插件可以选择裁剪框的尺寸比例,可以设置高宽尺寸,同时可以设置图片翻转角度,当然也支持图片的缩放,裁剪框也可以用鼠 ...

  2. [转]PLSQL Developer软件使用大全

    原文地址:https://www.cnblogs.com/lhrbest/p/6493218.html 第一章 PLSQL Developer特性 PL/SQL Developer是一个集成开发环境, ...

  3. 解密SVM系列(二):SVM的理论基础

    上节我们探讨了关于拉格朗日乘子和KKT条件.这为后面SVM求解奠定基础,本节希望通俗的细说一下原理部分. 一个简单的二分类问题例如以下图: 我们希望找到一个决策面使得两类分开.这个决策面一般表示就是W ...

  4. UIButton的竖排图片和文本

    UIButton的竖排图片和文本html, body {overflow-x: initial !important;}.CodeMirror { height: auto; } .CodeMirro ...

  5. css部分样式资料

    1. css字体 Lato,"Helvetica Neue","Segoe UI",Helvetica,Arial,sans-serif

  6. 为什么hash作为内存使用的经典数据结构?

    听到这样说法:hash是内存中使用的经典数据结构.内存是典型的随机访问设备. 为什么hash这种数据结构很适合内存使用呢?如何理解内存是随机访问设备呢? 因为我想知其所以然,如何理解背后的原因,我花费 ...

  7. Windows系统32位、64位DLL文件的存放位置

    查资料时无意中发现,Windows系统存放DLL的文件路径似乎有点蹊跷: 32位的DLL存放在C:\Windows\SysWOW64,而64位的DLL存放在C:\Windows\System32.即使 ...

  8. ArcEngine下SceneControl叠加影像数据(构建三维地形)

    载入完TIN数据后.须要在三维物体上描绘细节.即纹理:建立DEM表面点与纹理空间点的关系,即纹理映射.叠加影像数据就是把影像看作纹理.将其贴在地形表面,让其具有地形起伏的三维效果. 这里与GlobeC ...

  9. JS BUG 传递数字过大,数据值会变化

    如果要在js函数中传递大整型数值,一定要用字符串,否则会出现精度不准确 function testfun('2345234523452141234123412341234523452345123') ...

  10. Spring Boot 自定义属性 以及 乱码问题

    自定义属性 使用随机数及自定义配置类 中文乱码问题 1添加配置 2设置文件类型 1IDEA 2eclipse 自定义属性 application.properties提供自定义属性的支持,这样我们就可 ...