20160825
Unix环境高级编程-线程与线程控制总结
1.两个线程ID进行比较
函数:
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);
应用场景:
2.获取自身的线程ID
函数:
#include <pthread.h>
pthread_t pthread_self(void);
应用场景:
1.程序调试过程中打印线程ID有时是非常有用的。
2.用线程ID标示工作队列数据结构,线程池中不同线程通过ID识别处理队列中相同ID的工作。
3.线程的创建
函数:
#include <pthread.h>
int pthread_create(pthread_t *, const pthread_attr_t *,
void *(*start_rtn)(void), void *restrict arg);
注意:
1.主线程和新线程之间的竞争。
2.主线程不休眠,有可能新线程还没有运行之前整个进程可能就已经终止。这种特征依赖于OS中线程实现和调度算法。
3.LinuxOS使用clone系统调用来实现pthread_create,故主线程和新线程的父进程ID不同。clone创建子进程,可以共享父进程一定数量的执行环境(文件描述符和内存)。
4.线程的终止
函数:
#include <pthread.h>
int pthread_exit(void *rval_ptr);
int pthread_join(pthread_t thread, void **rval_ptr);
注意:
进程中任一线程调用exit,_exit,那么整个进程就会终止。整个进程不终止情况下结束单个线程,三种方式:
1.线程执行完,直接返回退出。
2.线程被同一进程中的其他线程取消pthread_join。
3.线程调用pthread_exit。
其他函数:
int pthread_cancel(pthread_t tid); /*请求控制流的非正常退出*/
void pthread_cleanup_push(void (*rtn)(void *), void *arg);/*建立线程清理处理程序*/
void pthread_cleanup_pop(int execute); /*执行线程清理处理程序*/
5.使线程进入分离状态
函数:
#include <pthread.h>
int pthread_detach(pthread_t tid);
6.线程互斥量
6.1互斥量初始化与销毁
函数:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
注意:
1.互斥变量用pthread_mutex_t数据类型表示。
2.使用互斥变量之前,必须首先初始化,也可以把它设置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量)。
3.动态分配(malloc)互斥量,在释放内存前需要调用xxx_destroy()函数。
6.2互斥量加解锁
函数:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
注意:
1.使用xxx_trylock线程不被阻塞,不能锁住则返回EBUSY。
2.避免死锁:两个线程对两个互斥量同时加锁,如果一个线程以与另一个线程相反的顺序锁住互斥量,则才可能出现死锁,如果以相同的顺序加锁,则可避免死锁。
3.锁的粒度:太粗,多线程阻塞等待相同的锁,并发性的改善微乎其微;太细,代码变复杂,锁的开销很大。
7.线程读写锁
7.1读写锁初始化与销毁
函数:
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
7.2读写锁加解锁
函数:
#include <pthread.h>
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);
注意:
1.作业请求队列由单个读写锁保护,以此实现多个工作线程获取由单个主线程分配给它们的作业。示例“程序清单11-8使用读写锁”。
2.读写锁非常适合于对数据结构读的次数远大于写的情况,多个线程可以同时读,故并行性比互斥量更高。
8.线程条件变量
8.1条件变量初始化与销毁
函数:
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);
int pthread_cond_destroy(pthread_cond_t *cond);
注意:
1.条件变量可以用两种方式初始化:用常量PTHREAD_COND_INITIALIZER或使用pthread_cond_init函数。
8.2条件变量等待与信号
函数:
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *timeout);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
注意:
1.timeout时间值是一个绝对数而不是相对数,可以使用gettimeofday获取当前时间、使用maketimeout进行时间格式转换。
2.条件变量给多个线程提供了一个会和场所。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生。
应用模板:
struct msg *workq;
pthread_cond_t qready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_ INITIALIZER;
pthread#1:{
pthread_mutex_lock(&qlock);
while (workq == NULL)
pthread_cond_wait(&qready, &qlock);
… … /*出队等等操作*/
pthread_mutex_unlock(&qlock);
}
pthread#2:{
pthread_mutex_lock(&qlock);
… … /*入队等等操作*/
pthread_mutex_unlock(&qlock);
pthread_cond_signal(&qready);
}
9.线程的控制
9.1线程限制于属性
9.2线程同步属性与重入
9.3线程私有数据
9.4线程与信号、fork、I/O