条件变量,条件锁,互斥锁的简单理解

来源:互联网 发布:matlab从txt读取数据 编辑:程序博客网 时间:2024/05/15 23:45
看了一些网上有关条件锁的讲解,一般都讲得晦涩难懂,都是术语的感觉,看了让人似乎明白了一点,又有很多疑惑,所以我决定写下我自己的简单理解。在写条件锁之前,先讲讲互斥锁,请看例子:1,不使用互斥锁的情况:
#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>#include <string.h>pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;void printf_thread1(int n){    int i;    //pthread_mutex_lock(&mylock);    while(n--)    {        printf("this is thread111.and ##%d\n",n+1);        for(i=0;i<1000000;i++){i++;i--;}    }    /pthread_mutex_unlock(&mylock);}void printf_thread2(int n){    int i;    printf("hello xue,I like you very much!\n");    //pthread_mutex_lock(&mylock);    while(n--)    {        printf("this is thread222.and ##%d\n",n+1);        for(i=0;i<1000000;i++){i++;i--;}    }       //pthread_mutex_unlock(&mylock);}int main(){  pthread_t tid1,tid2;  int err;  void *tret;  err=pthread_create(&tid1,NULL,printf_thread1,10);//创建线程  if(err!=0)  {    printf("pthread11_create error:%s\n",strerror(err));    exit(-1);  }  err=pthread_create(&tid2,NULL,printf_thread2,10);  if(err!=0)  {    printf("pthread22_create error:%s\n",strerror(err));     exit(-1);  }  err=pthread_join(tid1,&tret);//阻塞等待线程id为tid1的线程,直到该线程退出  if(err!=0)  {    printf("can not join with thread11:%s\n",strerror(err));    exit(-1);  }  printf("thread 11 exit code %d\n",(int)tret);  err=pthread_join(tid2,&tret);  if(err!=0)  {    printf("can not join with thread22:%s\n",strerror(err));    exit(-1);  }  printf("thread 22 exit code %d\n",(int)tret);  return 0;}

输出结果为:
这里写图片描述
可以看到线程1和线程2是交替执行的,而且每次的结果都有可能不同,造成原因是多线并发机制所致。

因此,我们把这个例子改成有锁的情况,改起来也很方便,就是把注释去掉就可以了:

#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>#include <string.h>pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;void printf_thread1(int n){    int i;    pthread_mutex_lock(&mylock);    while(n--)    {        printf("this is thread111.and ##%d\n",n+1);        for(i=0;i<3000000;i++){i++;i--;}    }    pthread_mutex_unlock(&mylock);}void printf_thread2(int n){    int i;    printf("hello xue,I like you very much!\n");    pthread_mutex_lock(&mylock);    while(n--)    {        printf("this is thread222.and ##%d\n",n+1);        for(i=0;i<3000000;i++){i++;i--;}    }       pthread_mutex_unlock(&mylock);}int main(){  pthread_t tid1,tid2;  int err;  void *tret;  err=pthread_create(&tid1,NULL,printf_thread1,10);//创建线程  if(err!=0)  {    printf("pthread11_create error:%s\n",strerror(err));    exit(-1);  }  err=pthread_create(&tid2,NULL,printf_thread2,10);  if(err!=0)  {    printf("pthread22_create error:%s\n",strerror(err));     exit(-1);  }  err=pthread_join(tid1,&tret);//阻塞等待线程id为tid1的线程,直到该线程退出  if(err!=0)  {    printf("can not join with thread11:%s\n",strerror(err));    exit(-1);  }  printf("thread 11 exit code %d\n",(int)tret);  err=pthread_join(tid2,&tret);  if(err!=0)  {    printf("can not join with thread22:%s\n",strerror(err));    exit(-1);  }  printf("thread 22 exit code %d\n",(int)tret);  return 0;}

此时输出的结果为:
这里写图片描述
可以看到当从线程1跳到线程2的时候,只执行了加锁前的一句,直到线程1执行完,线程2才开始执行。现在体会到互斥锁的作用了吧!不客气呦。。。

下面再在这个例子上加入条件锁,来探究条件锁的用法,在贴代码前,我先说下我怎么用条件锁。我们做这样的改变,当线程1执行到n<6时,重新开始线程2执行,等到线程2执行完,又回到线程1,执行剩下部分。
代码如下:

#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <unistd.h>#include <string.h>pthread_mutex_t mylock=PTHREAD_MUTEX_INITIALIZER;pthread_cond_t mycond;void printf_thread1(int n){    int i;    pthread_mutex_lock(&mylock);    while(n--)    {        printf("this is thread111.and ##%d\n",n+1);        for(i=0;i<3000000;i++){i++;i--;}        if(n==5)            pthread_cond_wait(&mycond,&mylock);    }    pthread_mutex_unlock(&mylock);}void printf_thread2(int n){    int i;    printf("hello xue,I like you very much!\n");    pthread_mutex_lock(&mylock);    pthread_cond_signal(&mycond);    while(n--)    {        printf("this is thread222.and ##%d\n",n+1);        for(i=0;i<3000000;i++){i++;i--;}    }       pthread_mutex_unlock(&mylock);}int main(){  pthread_t tid1,tid2;  int err;  void *tret;  err=pthread_create(&tid1,NULL,printf_thread1,10);//创建线程  if(err!=0)  {    printf("pthread11_create error:%s\n",strerror(err));    exit(-1);  }  err=pthread_create(&tid2,NULL,printf_thread2,10);  if(err!=0)  {    printf("pthread22_create error:%s\n",strerror(err));     exit(-1);  }  err=pthread_join(tid1,&tret);//阻塞等待线程id为tid1的线程,直到该线程退出  if(err!=0)  {    printf("can not join with thread11:%s\n",strerror(err));    exit(-1);  }  printf("thread 11 exit code %d\n",(int)tret);  err=pthread_join(tid2,&tret);  if(err!=0)  {    printf("can not join with thread22:%s\n",strerror(err));    exit(-1);  }  printf("thread 22 exit code %d\n",(int)tret);  return 0;}

输出结果为:
这里写图片描述
可以看到线程1执行到##6时就跳到了线程2执行,直到线程2执行完了再回来执行。
所以条件锁的作用相当于一个借锁的过程,pthread_cond_wait(&mycond,&mylock)这一语句,使得线程1获得的锁解开了,被移交到线程2(相当于借),此时线程1相当于挂起了,这里还涉及到了借的前提,就是必须要有锁,所以这一语句会有两个参数,一个是本身这个变量mycond,另一个是要借的锁mylock;而线程2中pthread_cond_signal(&mycond)这一语句有点像还锁,但有不是,因为不是立即还,而是要等线程2执行完了才还,所以这句话是赋予线程1继续拥有锁的权利,也就是把线程1重新放到等待队列中。
好了,现在你应该对互斥锁 下面这些概念有进一步的形象概念了吧:
阻塞在条件变量上pthread_cond_wait
解除在条件变量上的阻塞pthread_cond_signal
阻塞直到指定时间pthread_cond_timedwait
释放阻塞的所有线程pthread_cond_broadcast
释放条件变量pthread_cond_destroy
啦啦啦啦,总算写完了:

再贴一段别人对条件锁理解的形象比喻:
条件锁其实就是一个普通的锁加上了一个条件,如下面两行代码

//create a new lockprivate static Lock lock = new ReentrantLock();

//craete a conditionprivate static Condition newDeposit = lock.newCondition();

,重要的不是表象,是为什么需要这个条件锁,假设你有一个银行账户,密码你和你老婆都知道,你负责存钱,你老婆负责取钱,对存钱和取钱的代码都加了锁,所以是可以同步的。诶,平常存啊取的都挺好的,结果你俩矛盾了,你不去存钱,诶银行发现你老婆仍然可以取,而且透支了,你愿意不?银行愿意不?当然不愿意,也许你马上想到了,诶,我可以在取钱的时候加个条件去判断下,如果够取,那就让这个线程来取钱,否则呢?关键是这个否则呢?把这个线程干掉?不人道吧,让人家自己过N年后来取?这也不人道啊,评啥不是你通知人家老公存钱了,老婆过来看看,看够取不?诶,这个条件锁他就是这个为别人考虑的东西,你老婆一旦发现钱不够取了,他就打电话给你,嘿,小伙子,快点存钱,你说我有事,等会在存,等了很久,你存了一点,好,你在打电话给她,说,你可以去取取看,看过不,不够在打电话给我,够了直接取了就是。

饿死了,吃饭去

0 0