Linux 下POSIX线程
使用threadid标识一个线程。
创建线程的函数如下:
1: #include <pthread.h>
2:
3: int pthread_create(
4: pthread_t *restrict tidp,
5: const pthread_attr_t *restrict attr,
6: void *(*start_rtn)(void *), void *restrict arg);
判断两个线程是否相同
1: #include <pthread.h>
2:
3: int pthread_equal(pthread_t tid1, pthread_t tid2)
获取本线程的线程id
1: #include <pthread.h>
2:
3: pthread _t pthread_self(void);
线程终止
1: #include <pthread.h>
2:
3: void pthread_exit(void *rval_ptr);
4:
5: int pthread_join(pthread_t thread, void **rval_ptr);
一个线程可以要求另外一个线程被终止:
1: #include <pthread.h>
2:
3: void pthread_cancel(pthread_t tid)
线程cacel的取消由state和type决定。相关函数如下:
1: #include <pthread.h>
2: int pthread_setcancelstate(int state, int *oldstate);
3:
4: int pthread_setcanceltype(int type, int *oldtype);
5:
6: void pthread_testcancel(void);
pthread_setcancelstate 原子的设置线程的state,并返回之前的状态(oldstate)。可能取值为:PTHREAD_CANCEL_ENABLE 和 PTHREAD_CANCEL_DISABLE
pthread_setcanceltype 原子的设置线程的type,并返回之前的type。可能的取值为:PTHREAD_CANCEL_DEFERRED 和 PTHREAD_CANCEL_ASYNCHRONOUS
新创建的线程的state和type默认分别为PTHREAD_CANCEL_ENABLE 和 PTHREAD_CANCEL_DEFERRED
这些属性需要再开始设置,而不能在线程运行中修改。
1: #include <pthread.h>
2:
3: void pthread_cleanup_push(void (*rtn)(void *), void *arg);
4: void pthread_cleanup_pop(int execute);
这两个函数维护一个函数指针的Stack,可以把函数指针和函数参数值push/pop。执行的顺序则是从栈顶到栈底,也就是和push的顺序相反。
在下面情况下pthread_cleanup_push所指定的thread cleanup handlers会被调用:
a. 调用pthread_exit
b. 相应cancel请求
c. 以非0参数调用pthread_cleanup_pop()。(如果以0调用pthread_cleanup_pop(),那么handler不会被调用
有一个比较怪异的要求是,由于这两个函数可能由宏的方式来实现,因此这两个函数的调用必须得是在同一个Scope之中,并且配对,因为在pthread_cleanup_push的实现中可能有一个{,而pthread_cleanup_pop可能有一个}。因此,一般情况下,这两个函数是用于处理意外情况用的,举例如下:
1: void *thread_func(void *arg)
2: {
3: pthread_cleanup_push(cleanup, “handler”)
4:
5: // do something
6:
7: Pthread_cleanup_pop(0);
8: return((void *)0);
9: }
注: 个人测试,pthread_cleanup_push 和pthread_cleanup_pop的个数也要一致。
线程同步
互斥量Mutex
同一时刻只能有一个线程拿到锁
创建和关闭的方法:
1: #include <pthread.h>
2:
3: int pthread_mutex_init(
4: pthread_mutex_t *restrict mutex,
5: const pthread_mutexattr_t *restrict attr)
6:
7: int pthread_mutex_destroy(pthread_mutex_t *mutex);
加锁解锁的方法:
1: #include <pthread.h>
2:
3: int pthread_mutex_lock(pthread_mutex_t *mutex);
4:
5: int pthread_mutex_trylock(pthread_mutex_t *mutex);
6:
7: int pthread_mutex_unlock(pthread_mutex_t *mutex);
读写锁
读写锁有三种状态
i. 一个或者多个线程获得读锁,其他线程无法获得写锁
ii. 一个线程获得写锁,其他线程无法获得读锁
iii. 没有线程获得此读写锁
创建和关闭的办法
1: #include <pthread.h>
2:
3: int pthread_rwlock_init(
4: pthread_rwlock_t *restrict rwlock,
5: const pthread_rwlockattr_t *restrict attr)
6:
7: int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
加锁解锁的办法:
1: #include <pthread.h>
2:
3: int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
4:
5: int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
6:
7: int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
8:
9: int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
10:
11: int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
Conditional Variable
条件变量是使得线程等待在一个条件上,直到其他的线程触发条件满足。
条件必须被Mutex保护起来
b. 类型为:pthread_cond_t,必须被初始化为PTHREAD_COND_INITIALIZER(用于静态分配的条件,等价于pthread_cond_init(…, NULL))或者调用pthread_cond_init
创建和销毁的办法:
1: #include <pthread.h>
2:
3: int pthread_cond_init(
4: pthread_cond_t *restrict cond,
5: const pthread_condxattr_t *restrict attr)
6:
7: int pthread_cond_destroy(pthread_cond_t *cond);
等待条件发生的方法:
1: #include <pthread.h>
2:
3: int pthread_cond_wait(
4: pthread_cond_t *restrict cond,
5: pthread_mutex_t *restrict mutex);
6:
7: int pthread_cond_timedwait(
8: pthread_cond_t *restrict cond,
9: pthread_mutex_t *restrict mutex,
10: const struct timespec *restrict timeout);
pthread_cond_wait函数用于等待条件发生(=true)。pthread_cond_timedwait类似,只是当等待超时的时候返回一个错误值ETIMEDOUT。超时的时间用timespec结构指定。此外,两个函数都需要传入一个Mutex用于保护条件
等待时间的结构:
1: struct timespec {
2: time_t tv_sec; /* seconds */
3: long tv_nsec; /* nanoseconds */
4: };
注意timespec的时间是绝对时间而非相对时间,因此需要先调用gettimeofday函数获得当前时间,再转换成timespec结构,加上偏移量。
通知条件满足的函数:
1: #include <pthread.h>
2:
3: int pthread_cond_signal(pthread_cond_t *cond);
4:
5: int pthread_cond_broadcast(pthread_cond_t *cond);
两者的区别是前者会唤醒单个线程,而后者会唤醒多个线程。
补充(2013-09-07):
面试中提到条件变量,涉及到一个问题,条件变量在使用互斥锁的情况下,会有多个线程同时进入到wait状态吗?
解答: 是可能的。因为pthread_cond_wait函数会释放锁,并将当前线程加入条件的等待队列中。在条件满足以后,会重新在获取到锁。即从函数返回的时候是获取锁的状态。 这样由于锁是释放的,因此是可能多个都进入到wait状态的。
而pthread_cond_signal会唤醒特定的线程,而pthread_cond_broadcast是唤醒所有阻塞在该条件变量上的线程。但是即使唤醒全部的阻塞线程,他们也是需要竞争所然后执行的。
测试代码
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
pthread_mutex_t cond_lock;
pthread_cond_t cond_t;
void* Consumer(void* arg) {
pthread_mutex_lock(&cond_lock);
printf("Run Consumer %lu\n", pthread_self());
pthread_cond_wait(&cond_t, &cond_lock);
printf("After Wait %lu \n", pthread_self());
sleep(3);
pthread_mutex_unlock(&cond_lock);
return 0;
}
void* Producer(void* arg) {
pthread_mutex_lock(&cond_lock);
printf("Run Producer %lu \n", pthread_self());
// pthread_cond_signal(&cond_t);
pthread_cond_broadcast(&cond_t);
printf("After Signal %lu \n", pthread_self());
pthread_mutex_unlock(&cond_lock);
return 0;
}
int main(int argc, char** argv) {
pthread_cond_init(&cond_t, 0);
pthread_mutex_init(&cond_lock, 0);
pthread_t t1, t2, t3;
pthread_create(&t1, 0, Consumer, 0);
pthread_mutex_lock(&cond_lock);
sleep(1);
pthread_mutex_unlock(&cond_lock);
pthread_create(&t2, 0, Consumer, 0);
pthread_mutex_lock(&cond_lock);
sleep(1);
pthread_mutex_unlock(&cond_lock);
pthread_create(&t3, 0, Producer, 0);
pthread_mutex_lock(&cond_lock);
sleep(1);
pthread_mutex_unlock(&cond_lock);
sleep(5);
return 0;
}
执行结果:
当使用pthread_cond_signal如下:
当使用pthread_cond_broadcast
而测试时,对于使用pthread_cond_wait,两个线程同时被唤醒,但是后面的一个需要等待前面的释放了锁之后才能执行,即再其sleep之后释放所才执行
refer:Linux Thread 介绍总结
http://www.cnblogs.com/zhenjing/archive/2010/12/27/cancel_thread.html