1.互斥量
互斥变量用pthead_mutex_t数据类型来表示,在使用互斥变量之前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量),也可以能过调用pthread_mutex_init函数进行初始化。如果动态地分配互斥量(例如通过调用malloc)函数,那么释放内存前需要使用pthread_mutex_destroy.
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexarrt_t * restrict arrt);
int pthread_mutex_destroy(pthread_mutex_t &mutex);
返回值:成功返回0,否则返回错误编号。
要用默认的属性初始化互斥量,只需把attr设置为NULL。
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回0,否则返回错误编号。
- <span style="background-color: #ffffff; font-size: medium;">#include <stdlib.h>
- #include <pthread.h>
- struct foo {
- int f_count;
- pthread_mutex_t f_lock;
- /* ... more stuff here ... */
- };
- struct foo *
- foo_alloc(void) /* allocate the object */
- {
- struct foo *fp;
- if ((fp = malloc(sizeof(struct foo))) != NULL) {
- fp->f_count = 1;
- if (pthread_mutex_init(&fp->f_lock, NULL) != 0) {
- free(fp);
- return(NULL);
- }
- /* ... continue initialization ... */
- }
- return(fp);
- }
- void
- foo_hold(struct foo *fp) /* add a reference to the object */
- {
- pthread_mutex_lock(&fp->f_lock);
- fp->f_count++;
- pthread_mutex_unlock(&fp->f_lock);
- }
- void
- foo_rele(struct foo *fp) /* release a reference to the object */
- {
- pthread_mutex_lock(&fp->f_lock);
- if (--fp->f_count == 0) { /* last reference */
- pthread_mutex_unlock(&fp->f_lock);
- pthread_mutex_destroy(&fp->f_lock);
- free(fp);
- } else {
- pthread_mutex_unlock(&fp->f_lock);
- }
- }
- </span>
2.避免死锁
如果线程试图对同一个互斥量加锁两次,那么它自身就会陷入死锁状态。
一个线程试图以与另一个线程相反的顺序销售互斥量时,才可能出现死锁。
实例:
- <span style="background-color: #ffffff; font-size: medium;">#include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <pthread.h>
- #include <errno.h>
- pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- int lock_var;
- time_t end_time;
- void pthread1(void *arg);
- void pthread2(void *arg);
- int main(int argc, char *argv[])
- {
- pthread_t id1,id2;
- pthread_t mon_th_id;
- int ret;
- end_time = time(NULL)+10;
- /*互斥锁初始化*/
- pthread_mutex_init(&mutex,NULL);
- /*创建两个线程*/
- ret=pthread_create(&id1,NULL,(void *)pthread1, NULL);
- if(ret!=0)
- perror("pthread cread1");
- ret=pthread_create(&id2,NULL,(void *)pthread2, NULL);
- if(ret!=0)
- perror("pthread cread2");
- pthread_join(id1,NULL);
- pthread_join(id2,NULL);
- exit(0);
- }
- void pthread1(void *arg)
- {
- int i;
- while(time(NULL) < end_time)
- {
- /*互斥锁上锁*/
- if(pthread_mutex_lock(&mutex)!=0)
- {
- perror("pthread_mutex_lock");
- }
- else
- printf("pthread1:pthread1 lock the variable\n");
- for(i=0;i<2;i++){
- sleep(1);
- lock_var++;
- }
- /*互斥锁接锁*/
- if(pthread_mutex_unlock(&mutex)!=0){
- perror("pthread_mutex_unlock");
- }
- else
- printf("pthread1:pthread1 unlock the variable\n");
- sleep(1);
- }
- }
- void pthread2(void *arg)
- {
- int nolock=0;
- int ret;
- while(time(NULL) < end_time)
- {
- /*测试互斥锁*/
- ret=pthread_mutex_trylock(&mutex);
- if(ret==EBUSY)
- printf("pthread2:the variable is locked by pthread1\n");
- else
- {
- if(ret!=0)
- {
- perror("pthread_mutex_trylock");
- exit(1);
- }
- else
- printf("pthread2:pthread2 got lock.The variable is%d\n",lock_var);
- /*互斥锁接锁*/
- if(pthread_mutex_unlock(&mutex)!=0)
- {
- perror("pthread_mutex_unlock");
- }
- else
- printf("pthread2:pthread2 unlock the variable\n");
- }
- sleep(3);
- }
- } </span>
3.读写锁
1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)
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);
成功返回0,否则返回错误编号
实例:
- <span style="background-color: #ffffff; font-size: medium;">#include <stdlib.h>
- #include <pthread.h>
- struct job {
- struct job *j_next;
- struct job *j_prev;
- pthread_t j_id; /* tells which thread handles this job */
- /* ... more stuff here ... */
- };
- struct queue {
- struct job *q_head;
- struct job *q_tail;
- pthread_rwlock_t q_lock;
- };
- /*
- * Initialize a queue.
- */
- int
- queue_init(struct queue *qp)
- {
- int err;
- qp->q_head = NULL;
- qp->q_tail = NULL;
- err = pthread_rwlock_init(&qp->q_lock, NULL);
- if (err != 0)
- return(err);
- /* ... continue initialization ... */
- return(0);
- }
- /*
- * Insert a job at the head of the queue.
- */
- void
- job_insert(struct queue *qp, struct job *jp)
- {
- pthread_rwlock_wrlock(&qp->q_lock);
- jp->j_next = qp->q_head;
- jp->j_prev = NULL;
- if (qp->q_head != NULL)
- qp->q_head->j_prev = jp;
- else
- qp->q_tail = jp; /* list was empty */
- qp->q_head = jp;
- pthread_rwlock_unlock(&qp->q_lock);
- }
- /*
- * Append a job on the tail of the queue.
- */
- void
- job_append(struct queue *qp, struct job *jp)
- {
- pthread_rwlock_wrlock(&qp->q_lock);
- jp->j_next = NULL;
- jp->j_prev = qp->q_tail;
- if (qp->q_tail != NULL)
- qp->q_tail->j_next = jp;
- else
- qp->q_head = jp; /* list was empty */
- qp->q_tail = jp;
- pthread_rwlock_unlock(&qp->q_lock);
- }
- /*
- * Remove the given job from a queue.
- */
- void
- job_remove(struct queue *qp, struct job *jp)
- {
- pthread_rwlock_wrlock(&qp->q_lock);
- if (jp == qp->q_head) {
- qp->q_head = jp->j_next;
- if (qp->q_tail == jp)
- qp->q_tail = NULL;
- } else if (jp == qp->q_tail) {
- qp->q_tail = jp->j_prev;
- if (qp->q_head == jp)
- qp->q_head = NULL;
- } else {
- jp->j_prev->j_next = jp->j_next;
- jp->j_next->j_prev = jp->j_prev;
- }
- pthread_rwlock_unlock(&qp->q_lock);
- }
- /*
- * Find a job for the given thread ID.
- */
- struct job *
- job_find(struct queue *qp, pthread_t id)
- {
- struct job *jp;
- if (pthread_rwlock_rdlock(&qp->q_lock) != 0)
- return(NULL);
- for (jp = qp->q_head; jp != NULL; jp = jp->j_next)
- if (pthread_equal(jp->j_id, id))
- break;
- pthread_rwlock_unlock(&qp->q_lock);
- return(jp);
- }
- </span>
这个例子中,不管什么时候需要增加一个作业也不能队列中或者从队列中删除作业,都用写模式锁住队列的读写锁。不管何时搜索队列,首先需要获取读模式下的锁,允许所有的工作线程并发地搜索队列。在这种情况下,只有线程搜索队列的频率远远高于增加或者删除作业时,使用读写锁才可能改善性能。
4.条件变量
静态创建:pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
动态创建:pthread_cond _t cond;
pthread_cond_init(&cond,NULL);
其中的第二个参数NULL表示条件变量的属性,虽然POSIX中定义了条件变量的属性,但在LinuxThread中并没有实现,因此常常忽略
实例:
- <span style="font-size: medium;">#include<stdio.h>
- #include<pthread.h>
- pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
- int count=5;
- void *decrement(void *arg)
- {
- while(1)
- {
- pthread_mutex_lock(&mutex);
- while(count<=0)
- {
- printf("count<=0,thread1 is hanging!\n");
- pthread_cond_wait(&cond,&mutex);
- sleep(1);
- printf("sleep!\n");
- }
- count=count-1;
- pthread_mutex_unlock(&mutex);
- if(count==9)
- {
- printf("count=9,thread1 is over!\n");
- return NULL;
- }
- }
- }
- void *increment(void *arg)
- {sleep(1);
- while(1)
- {
- pthread_mutex_lock(&mutex);
- count=count+1;
- if(count>0)
- {
- printf("count=%d,change cond state!\n",count);
- pthread_cond_signal(&cond);
- }
- pthread_mutex_unlock(&mutex);
- if(count==10)
- {
- printf("count=10,thread2 is over!\n");
- return NULL;
- }
- }
- }
- int main()
- {
- int i1=1,i2=1;
- pthread_t id1,id2;
- pthread_mutex_init(&mutex,NULL);
- pthread_cond_init(&cond,NULL);
- pthread_create(&id1,NULL,decrement,NULL);
- pthread_create(&id2,NULL,increment,NULL);
- i2=pthread_join(id2,NULL);
- i1=pthread_join(id1,NULL);
- if((i2==0)&&(i1==0))
- {
- printf("count=%d,the main thread!\n",count);
- pthread_cond_destroy(&cond);
- pthread_mutex_destroy(&mutex);
- return 0;
- }
- }</span>