《APUE》读书笔记第十一章-线程
本章主要介绍了线程,了解如何使用多线程在单进程环境中来执行多任务。由于多个线程共享其进程空间,所以必须采用同步的机制来保护数据的一致性。
一.线程的概念
典型的Unix系统都可以看成只有一个控制线程,一个进程在同一时刻只能做一件事。但有了多线程,我们可以设计成在同一时刻进程能做不止一件事,每个线程处理各自独立的任务。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本、程序的全局内存和堆内存、栈以及文件描述符。
二.线程标识
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);//若相等则返回非0值,否则返回0 pthread_t pthread_self(void);//返回调用线程的线程ID
三、线程创建、终止与清理
int pthread_create(pthread_t *tid,const pthread_attr_t* attr,
void* (*start)(void*),void* arg);
//返回值:若成功则返回0,否则返回错误编号
单个线程可以通过下列三种方式退出,在不终止整个进程的情况下停止它的控制流.
- 线程只是从启动例程中返回,返回值是线程的退出码。
- 线程可以被同一进程中的其他线程取消。
- 线程调用pthread_exit。
但是这两个函数有一个限制,由于它们可以实现为宏,所以必须在线程相同的作用域中以匹配对的形式使用,pthread_cleanup_push的宏定义可包含字符{,在这种情况下对应的匹配字符}就要在pthread_cleanup_pop定义中出现。
int pthread_join(pthread_t tid,void ** ptr);
//若成功则返回0,否则返回错误编号
调用线程将一直阻塞,直到指定的线程调用pthread_exit、从启动例程中返回或被取消。ptr将包含返回码。
如果线程采用pthread_self函数使其处于分离状态,pthread_join调用就会失败.返回EINVAL.
void pthread_cancel(pthread_t tid);//成功返回0,否则返回错误编号
线程可以安排它退出时的需要调用的函数,这与进程可以用atexit函数安排进程退出时需要调用的函数类似。线程可以建立多个清理处理程序,处理程序在栈中,也就是说他们的顺序与它们注册的顺序相反。
void pthread_cleanup_push(void (*rtn)(void*),void *arg);
void pthread_cleanup_pop(int execute);
当线程执行以下动作时调用清理函数,调用参数为arg.
- 调用pthread_exit时
- 响应取消请求时
- 用非零execute参数调用pthread_cleanup_pop时
如果execute参数置为0,清理函数将不被调用。
四.线程同步
当多个线程共享相同内存时,为了保持数据共享的一致性,我们采取线程同步的机制。线程同步有四种方法:
1.互斥量
可以通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据.互斥量(mutex)从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁后,任何其他试图再次对互斥量加锁的线程将会被阻塞直到当前线程释放该互斥锁。
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex); int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
如果线程不希望被阻塞,它可以使用pthread_mutex_trylock尝试对互斥量进行加锁。如果调用pthread_mutex_trylock时互斥量处于未锁住的状态,那么pthread_mutex_trylock将锁住互斥量,不会出现阻塞并返回0.否则pthread_mutex_trylock就会失败,不能锁住互斥量,而返回EBUSY.
2.读写锁
读写锁与互斥锁类似,不过读写锁允许更高的并行性.读写锁有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。
当读写锁时写加锁状态时,在这个锁被解锁前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁在读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进行加锁,它必须阻塞到所有的线程释放读锁。
读写锁也叫做共享-独占锁,当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockaddr_t* attr);
int pthread_rwlock_destroy(pthread_rwlock_t* rwlock);
//成功时返回0,否则返回错误编号 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
3.条件变量
条件变量给多个线程提供了一个会合的场所,条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
条件本身是由互斥量保护的。线程在改变条件状态时必须首先锁住互斥量,其他线程在获得互斥量之前不会察觉到这种改变,因为必须锁住互斥量以后才能计算条件。
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond); int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex_t *mutex,
struct timespec* timeout); int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
//成功返回0,失败则返回错误编号
#include <pthread.h>
struct msg* workq;
pthread_cond_t qready=PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock=PTHREAD_MUTEX_INITIALIZER; void process_msg(void){
struct msg* mp;
for(;;){
pthread_mutex_lock(&qlock);
while(qlock==NULL){
pthread_cond_wait(&qready,&qlock);
} mp=workq;
workq=mp->m_next;
pthread_mutex_unlock(&qlock);
}
} void enqueue_msg(struct msg* mp){
pthread_mutex_lock(&qlock);
mp->m_next=workq;
workq=mp;
pthread_mutex_unlock(&qlock);
pthread_cond_signal(&qready);
}
《APUE》读书笔记第十一章-线程的更多相关文章
- 《Linux内核设计与实现》第五周读书笔记——第十一章
<Linux内核设计与实现>第五周读书笔记——第十一章 20135301张忻 估算学习时间:共2.5小时 读书:2.0 代码:0 作业:0 博客:0.5 实际学习时间:共3.0小时 读书: ...
- 《UNIX环境高级编程》(APUE) 笔记第十一章 - 线程
11 - 线程 Github 地址 1. 线程概念 典型的 UNIX进程 可以看成只有一个 控制线程 :一个进程在某一时刻只能做一件事情.有了 多个控制线程 ,就可以把进程设计成在某一时刻能够做不止一 ...
- 《利用python进行数据分析》读书笔记--第十一章 金融和经济数据应用(一)
自2005年开始,python在金融行业中的应用越来越多,这主要得益于越来越成熟的函数库(NumPy和pandas)以及大量经验丰富的程序员.许多机构发现python不仅非常适合成为交互式的分析环境, ...
- C primer plus 读书笔记第十一章
本章标题是字符串和字符串函数.主要是了解和字符串有关的函数. 1.字符串表示和字符串I/O 主要内容:字符串常量和字符串数组的初始化,对比了指针和字符串. 其中要注意的是,数组初始化是从静态存储区把一 ...
- APUE读书笔记-第13章-守护进程
第13章 守护进程 13.1 引言 *守护进程也称精灵进程(daemon)是生存期较长的一种进程.它们常常在系统自举时启动,仅在系统关闭时才终止.因为它们没有控制终端,所以说它们是在后台运行的.UNI ...
- 《Unix环境高级编程》读书笔记 第11章-线程
1. 引言 了解如何使用多个控制线程在单进程环境中执行多个任务. 不管在什么情况下,只要单个资源需要在多个用户键共享,就必须处理一致性问题. 2. 线程概念 典型的Unix进程可以看成只有一个控制线程 ...
- 《Java并发编程实战》读书笔记-第2章 线程安全性
要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问. 修复多线程问题的方式: 不在线程之间共享该状态变量 将状态变量修改为不可变的变量 在访问状态变量时使用同步 ...
- APUE读书笔记-第17章-高级进程间通信
17.1 引言 *两种高级IPC:基于STREAMS的管道(STREAMS-based pipe)以及UNIX域套接字(UNIX domain socket)可以在进程间传送打开文件描述符.服务进程可 ...
- APUE读书笔记-第18章-终端I/O
18.1 引言 *终端I/O的用途很广泛,包括用于终端.计算机之间的直接连线.调制解调器以及打印机等等,所以终端I/O系统非常复杂 18.2 综述 *终端I/O有两种不同的工作模式: (1)规范模式输 ...
随机推荐
- MySQL 5.6 root密码丢失,使用mysqld --skip-grant-tables
MySQL 5.6 root密码丢失,(window平台)使用mysqld –skip-grant-tables启动MySQL服务,出现警告: 1 [Warning] TIMESTAMP with i ...
- traceroute小结 come from CSDN author:houdong
traceroute程序可以使我们看到IP数据报从一台主机传到另一台主机的所经过的路由,并且可以使用IP源站路由选项. traceroute取代IP RR的原因 1 不是所有的路由器都支持IP RR选 ...
- 基类方法的反隐藏 反private 秘籍
class GoodStudent:private Mentor,private Student { public : using Mentor::GetInfo; ///------------ ...
- angularjs学习笔记—事件指令
ngClick 适用标签:所有触发条件:单击 #html <div ng-controller="LearnCtrl"> <div ng-click=" ...
- ssm+jsp+自定义标签实现分页,可以通用(后端实现)
从controller到mapper.xml的后端实现 只梳理分页相关代码 1 controller里面相关 ModelAndView mv = new ModelAndView("/lis ...
- Builder模式的几个要点
1.Builder模式主要用于“分步骤构建一个复杂的对象”.在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化.2.变化点在哪里,封装哪里——Builder模式主要在于应对“复杂对象各 ...
- 自制单片机之七……扩展:DS18B20温度测量
DS18B20数字温度测量传感器,网上介绍很多,我就不罗嗦了.见图 DS18B20与前产品DS1820的不同: DS18B20继承了DS1820的全部优点,并做了如下改进 1.供电范围扩大为3.0-- ...
- bzoj4005[JLOI2015]骗我呢
http://www.lydsy.com/JudgeOnline/problem.php?id=4005 神题~远距离orz 膜拜PoPoQQQ大神 #include<cstdio> #i ...
- [VBA]根据身份证号码计算年龄的Excel函数
是的,昨天刚发表了一篇和Excel自定义函数有关的博客,今天又一篇,有凑数的嫌疑.但是,保存知识和传播知识本来就是写博客的初衷,所以也并不多余. 如果不知道什么是Excel自定义函数,请移步这里[1] ...
- 迅雷API:实现文件下载
今天到迅雷公司的SDK文档网站上逛了逛,竟然发现它们已经提供了完备的API接口,我心中不禁大喜,但是SDK资料中的原版开发文件已经很难找到了,幸运的是我在github上搜索到了所需的文件,在这里我已 ...