第11章线程
UNIX操作系统中多线程的存在允许同一时间处理多件事情
线程包含了表示进程内执行环境必需的信息,其中包括进程中标识现场的线程ID,一组寄存器值,栈,调度优先级和策略等等
11.1 线程标识(pthread_id)
#include<pthread.h>
Int pthread_equal(pthread_t tid1,pthread_ttid2); //比较两个线程ID
Pthread_t pthread_self(void);//获得自身线程ID
11.2 线程创建
Int pthread_create(pthread_t *restricttidp,const pthread_attr_t* restrict attr,void *(*start_rtn)(void),void*restrict arg);
Tidp:新创建线程的线程ID
Attr:定制线程的属性
Start_rtn:新创建的线程开始执行的入口
Arg:start_rtn函数需要的参数,若参数个数>1,则需要将多个参数封装在一个结构中
11.3 线程终止
如果任一线程调用exit,_Exit或者_exit,整个进程会终止
Void pthread_exit(void *rval_ptr); //终止单一线程,且不会造成整个进程的终止
Int pthread_join(pthread_t thread,void**rval_ptr);//调用线程会一直阻塞,直到指定线程退出(包括调用pthread_exit,从启动例程返回或者被同一个进程的其他线程取消)
Rval_ptr:标识指定线程退出的方式(终止状态),退出码,返回码,取消码
11.4线程取消
Int pthread_cancel(pthread_t tid);//取消同一个进程的其他线程
11.5 线程清理函数
Void pthread_cleanup_push(void (*rtn)(void*),void *arg);//线程退出时的清理函数
Rtn:清理函数
Arg:函数参数
清理函数有效启动的三种情况:
1) 调用pthread_exit
2) 响应取消请求
3) 用非零execute参数调用pthread_cleanup_pop
清理函数的调用顺序和执行顺序相反
Int pthread_detach(pthread_t tid);//使得线程分离
11.6线程同步
线程同步的应用场景:当多个线程均共享同一片内存区域,且多个线程均能修改内存区域数据时,则会产生一致性问题,需要线程同步来解决(锁)
互斥量(pthread_mutex_t):本质上就是一把锁,当访问共享资源时,首先会对互斥量加锁,访问完成后再解锁
Int pthread_mutex_init(pthread_mutex_t*restrict mutex,const pthread_mutexattr_t * restrict attr);//对互斥量进行初始化
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);//互斥量尝试加锁(线程不阻塞),若刚好加锁互斥量,则不会阻塞并返回0,否则不能锁住互斥量且会返回EBUSY,能够有利的解决死锁问题
Int pthread_mutex_unlock(pthread_mutex_t*mutex);//互斥量解锁
锁的使用要找到折中方案,锁的粒度太大,会造成多个线程阻塞等待,而锁的粒度太小则会导致开销增大
读写锁的三种状态:读模式加锁状态,写模式加锁状态,不加锁状态,允许同一时间只有一个线程占有写模式的读写锁,多个线程占有读模式的读写锁,当读写锁处于写加锁状态时,所有试图对该锁加锁的线程均阻塞;当读写锁处于读模式状态时,所有试图以读模式对它进行加锁的线程均可以获得访问权限,但如果线程希望以写模式对此锁进行加锁,则必须阻塞等待全部的线程释放读锁(非常适合对数据结构的读多于写的情况),也称为共享-独占锁
Int pthread_rwlock_init(pthread_rwlock_t*restrict rwlock,const pthread_rwlockattr_t *restrict attr); //初始化读写锁
Int pthread_rwlock_destroy(pthread_rwlock_t*rwlock); //释放读写锁
Int pthread_rwlock_rdlock(pthread_rwlock_t*rwlock); //锁定读模式锁
Int pthread_rwlock_wrlock(pthread_rwlock_t*rwlock);//锁定写模式锁
Int pthread_rwlock_unlock(pthread_rwlock_t*rwlock);//解锁
Int pthread_rwlock_tryrdlock(pthread_rwlock_t*rwlock);//尝试锁定读模式锁
Int pthread_rwlock_trywrlock(pthread_rwlock_t*rwlock);//尝试锁定写模式锁
条件变量
线程在改变条件之前必须首先锁住互斥量(用互斥量保护条件变量),其他线程在获得互斥量前不会察觉到这种改变,因为必须锁定互斥量后才能计算条件。
Int pthread_cond_init(pthread_cond_t*restrict cond,pthread_condattr_t *restrict attr);//初始化条件变量
Int pthread _cond_destroy(pthread_cond_t*cond);//释放条件变量
Int pthread_cond_wait(pthread_cond_t*restrict cond,pthread_mutex_t *restrict mutex);//等待条件变量为真
Int pthread_cond_timedwait(pthread_cond_t*restrict cond,pthread_mutex_t *restrict mutex,const structtimespec *restrict timeout);//单位时间限制
Struct timespec{
Time_t tv_sec;
Long tv_nsec;
}//当前时间加上指定时间
Int pthread_cond_signal(pthread_cond_t*cond);//唤醒等待条件的某一个线程
Int pthread_cond_broadcast(pthread_cond_t*cond);//唤醒等待条件的全部线程