pthread是类Unix下的多线程库..最近学习了一下多线程的东东..这里总结下基本的用法
1.pthread_create(), pthread_exit(), pthread_cancel()
int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*routine)(void *), void *arg) : 创建一个线程..线程ID被赋予tid..线程属性为attr..线程执行函数为routine..其参数为arg..不过attr一般为NULL..就是在创建默认线程..
void pthread_exit(void *ret) : 退出线程..并将ret返回..其实这样同直接最后return ret是一个道理..但有一点区别..return的话..线程退出函数不执行的..这个后面会说到
int pthread_cancel(pthread_t tid) : 向tid发出cancel请求..上面的pthread_exit是退出自己的线程..但这个是本线程向tid申请退出..这个cancel申请不一定会执行..仅仅是发出这样的申请而已..不保证tid一定会退出
3.pthread_self(), pthread_equal()
pthread_t pthread_self() : 返回本线程的线程id
int pthread_equal(pthread_t tid1, pthread_t tid2) : pthread_t是不透明的结构..因此不能假设pthread_t类型..只能通过pthread_equal来比较其是否相等..0表示不等..非0表示相等
4.pthread_join(), pthread_detach()
线程之间需要进行通信..最简单的通信就是获取其返回值(就是pthread_exit或者return的那个值)..这两个函数就是拿来操作类似事情的..
int pthread_join(pthread_t tid, void **ret) : 本线程等待tid线程结束..并通过ret获得其返回值
int pthread_detach(pthread_t tid) : 取消对tid线程的joinable状态..这个需要解释一下..线程默认创建出来时..都是joinable的..也就是可以通过pthread_join获得返回值的..另一个线程可以得到某个线程的返回值..其实就表明某线程结束后..系统并没有释放其资源..而是等待某个线程来获取最后的信息..之后才释放其资源..我们有两种方法避免这种对系统资源的无效占据..一个是直接设置线程的属性(pthread_attr中有一项是关于detach的.)..另一个则是pthread_detach..表明tid线程我们不关系其返回值..tid结束后系统就直接收回其资源就可以了..
注意:这个tid可以是任意的线程id..包括自己..
5.pthread_attr_init(), pthread_attr_destroy()
上文说了..线程有一定的属性..而这个属性不能通过普通的赋值来操作..只能通过pthread的接口函数来操作
int pthread_attr_init(pthread_attr_t *attr) : 初始化线程属性attr..attr需要提前声明出一个实例才能操作..而这个函数仅仅是初始化attr..不对attr进行任何赋值
int pthread_attr_destroy(pthread_attr_t *attr) : 销毁线程属性..init之后一定要destroy这个属性..
属性是通过一系列pthread_attr_setXXX/pthread_attr_getXXX函数来设置或者取值的..下面会说到.
6.mutex
mutex有两种使用初始化的方式..一种是静态的方法..pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 这样的话就可以直接使用了..另一种则是动态方法..init和destroy必须配对使用
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr_t *attr) : 用attr初始化mutex..attr一般为NULL..则使用默认的属性
int pthread_mutex_destroy(pthread_mutex_t *mutex): 释放掉mutex..两函数必须配对使用..
int pthread_mutex_lock(pthread_mutex_t *mutex) : 锁住一个mutex..如果这个mutex被其他线程先锁住了..那么本线程就会阻塞..直到原线程释放掉锁..而本线程获得锁..并锁住mutex..也就是说本线程不会返回..直到mutex被本线程得到并锁住..
int pthread_mutex_unlock(pthread_mutex_t *mutex) : 释放掉mutex..一般来说..先lock..后unlock..否则会引起很多麻烦..\
int pthread_mutex_trylock(pthread_mutex_t *mutex) : 尝试得到一个mutex..如果这个mutex被其他线程锁住了..那么他会立即返回非0值..如果成功得到并锁住了mutex..则会返回0..一般我们都不需要对mutex函数的返回值检查..这个是个例外..只有返回值能确定我们是否得到了锁
使用mutex时最重要的一点是规范..1.lock/unlock的顺序必须统一..2.试图访问被mutex锁住的资源时需要遵循lock/unlock的规范..只要有一个线程不遵守规则..资源就会被破坏掉..3.如果有多个资源被多个mutex锁住..这些mutex的取得顺序必须是一致的..否则容易出现死锁..
7.rwlock
rwlock是一种特殊的锁..只能有一个写线程获得wlock..但是可以有可配置的数个读线程同时获得rlock..
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlockattr) : 初始化rwlockattr属性的rwlock..这个属性就包括上面说的有几个可读线程之类的属性..不过一般都设为NULL..初始化一个默认rwlock
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) : 收回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)
上面这五个函数和mutex的类似..只不过多了rdlock和wrlock的区别..当我们的操作大多数是读..或者对读操作没有限制时..我们就可以方便的将rdlock和wrlock进行区分..这样可以提高程序的性能
8.condition variable
条件变量可以让我们设定不同的条件..并让不同的线程等待在不同的条件上..这样一来我们可以区分不同线程来分配不同的条件.提高所谓的性能..
如同mutex一样..cond可以用两种方法初始化..一种是静态初始化..pthread_cond_t cond = PTHREAD_COND_INITIALIZER..另一种同样是动态的分配方法.
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
int pthread_cond_destroy(pthread_cond_t *cond)..还是如同mutex..不解释..
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 *abstime):
这两个函数结合了cond和mutex..我们有必要解释下cond的用法..我们应该先对mutex进行lock..然后检测条件是否满足..当线程检测到某一个条件不成立的时候(这个条件不是cond..而是我们期待的一个真正的条件)..我们就在一个cond上等待..这个cond叫什么无所谓..不过一个cond应该代表一个条件..这种等待是阻塞的..等待的同时..unlock掉了原来的mutex...当线程被signal唤醒时..它会检测mutex..如果正好没被锁..就会对mutex进行lock..如果没有的话..就会阻塞到等待mutex上..直到获得了这个mutex..
也就是这样一个流程
//一个等待条件的线程
pthread_mutex_lock(mutex);
if (condition is false)
pthread_cond_wait(cond, mutex) //等待对cond的唤醒..同时unlock掉mutex
//此处mutex已被本线程lock
//处理condition..
pthread_mutex_unlock(mutex);
timedwait仅仅是带上了一个时间限制..在时间限制之后..就直接返回一个错误..我们要通过检测才知道是真的条件被唤醒..还是过了时间限制..
int pthread_cond_signal(pthread_cond_t *cond)
int pthread_cond_broadcast(pthread_cond_t *cond)
这两个函数是用来唤醒等待在cond的线程..signal只唤醒一个..broadcast则是唤醒全部..
一般的流程如下
//处理并唤醒条件的线程
pthread_mutex_lock(mutex)
//处理condition
//条件满足了..我们就要signal一下下
pthread_cond_signal(cond)
//但是此时等待线程还没进行..它还没获得mutex..因为本线程还在lock中
pthread_mutex_unlock(mutex)
//好了..我们的等待线程可以运行了..
至于为什么这个进程前后要对mutex进行锁定..我们可以回忆下mutex的内容..condition是我们试图操作的资源..等待线程对其加锁了..所以为了规范性..所有线程都必须加锁..
当然..根据规范..等待线程使用if来检测条件是否成立是比较危险的..推荐用循环
while (condition is false)
pthread_cond_wait(cond, mutex)
cond并不是可以检测的东东..它只是一个代表我们等待条件的抽象的信号而已..其他进行可以signal通知我们cond代表的条件满足了..仅此..
还有很多设置属性的..我就不说了..以上就是pthread的基础内容了..多线程编程的难点不在于使用库..而在于对多线程的整体设计..多多练习..多多实践..我们才能得到合适的方法..