Linux 多线程编程(Pthread 库)学习笔记 三

来源:互联网 发布:js div靠右 编辑:程序博客网 时间:2024/05/20 04:10

 线程的数据处理 之 互斥锁


互斥锁

互斥锁用来保证一段时间内只有一个线程在执行一段代码
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直至调用pthread_mutex_unlock为止,均被上锁,即同一时间只能被一个线程调用执行。当一个线程执行到pthread_mutex_lock处时,如果该锁此时被另一个线程使用,那此线程被阻塞,即程序将等待到另一个线程释放此互斥锁

 

a线程先锁定互斥锁1,b线程先锁定互斥锁2,这时就出现了死锁。此时我们可以使用函数 pthread_mutex_trylock,它是函数pthread_mutex_lock的非阻塞版本,当它发现死锁不可避免时,它会返回相应的信息,程序员可以针对死锁做出相应的处理。另外不同的互斥锁类型对死锁的处理不一样,但最主要的还是要程序员自己在程序设计注意这一点。

 

条件变量
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是否满足。一般说来,条件变量被用来进行线程间的同步.

条件变量的结构为pthread_cond_t函数pthread_cond_init()被用来初始化一个条件变量。它的原型为:
extern int pthread_cond_init  __P ((pthread_cond_t *__cond,

                                                             __const pthread_condattr_t *__cond_attr));
其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。

结构 pthread_condattr_t是条件变量的属性结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可用,默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。注意初始化条件变量只有未被使用时才能重新初始化或被释放。

释放一个条件变量的函数为pthread_cond_ destroy(pthread_cond_t cond)。 

函数pthread_cond_wait()使线程阻塞在一个条件变量上。它的函数原型为:
extern int pthread_cond_wait __P ((pthread_cond_t *__cond,
                                                                pthread_mutex_t *__mutex));
线程解开mutex指向的锁并被条件变量cond阻塞。线程可以被函数pthread_cond_signal和函数 pthread_cond_broadcast唤醒,但是要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下一次唤醒。这个过程一般用while语句实现。

另一个用来阻塞线程的函数是pthread_cond_timedwait(),它的原型为:
extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,
                                                                          pthread_mutex_t *__mutex,

                                                                           __const struct timespec *__abstime));
它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。

 

函数pthread_cond_signal()的原型为:
extern int pthread_cond_signal  __P ((pthread_cond_t *__cond));
它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是,必须用保护条件变量的互斥锁来保护这个函数,否则条件满足信号又可能在测试条件和调用pthread_cond_wait函数之间被发出,从而造成无限制的等待

 

下面是使用函数pthread_cond_wait()和函数pthread_cond_signal()的一个简单的例子。

 #include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
using namespace std;


pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
int counter =0;
int estatus=-1;

void * decrement_count(void * argv);
void * increment_count(void * argv);

int main(int argc, char *argv[])
{
 printf("counter:%d\n",counter);
 pthread_t thrd1,thrd2;
 int ret;
 ret = pthread_create(&thrd1,NULL,decrement_count,NULL);
 if(ret)
 {
  perror("de1:");
  return 1;
 }
 
 ret = pthread_create(&thrd2,NULL,increment_count,NULL);
 if(ret)
 {
  perror("in1:");
  return 1;
 }

 int count=0;
 while(count!=20)
 {
  printf("counter:%d\n",counter);
  sleep(1);
 count++;
 }
 return 0;
}

void * decrement_count (void * argv)
{
 pthread_mutex_lock(&count_lock);
 while(counter==0)
  pthread_cond_wait(&count_nonzero,&count_lock);
 counter--;
 pthread_mutex_unlock(&count_lock);
 return &estatus;
}

void * increment_count(void * argv)
{
 pthread_mutex_lock(&count_lock);
   if(counter==0)
    pthread_cond_signal(&count_nonzero);
 counter++;
 pthread_mutex_unlock(&count_lock);
   return &estatus;
}

 

开始时 counter 为0,
ret = pthread_create(&thrd1,NULL,decrement_count,NULL)处生成一个thrd1线程运行decrement_count(),此线程内函数运行流程为:
锁定 互斥锁 count_lock,如果counter为0,此线程被阻塞在条件变量count_nonzero上.同时释放互斥锁count_lock.

 

与此同时主程序还在运行,创建另一个线程thrd2运行 increment_count,此线程内的函数流程如下:
锁定 互斥锁 count_lock,如果counter为0,唤醒在条件变量count_nonzero上的线程即thrd1.但是由于有互斥锁count_lock,thrd1还是在等待.然后count++,释放互斥锁,.......thrd1由于互斥锁释放,重新判断counter是不是为0,如果为0再把线程阻塞在条件变量count_nonzero上,但这时counter已经为1了.所以线程继续运行.counter--释放互斥锁......
与此主程序间隔打印counter运行一段时间退出.


 

后记,在编译的时候加上 -lpthread

 

原创粉丝点击