关于mutex与cond的用法

来源:互联网 发布:ecshop分销系统源码 编辑:程序博客网 时间:2024/05/21 06:31

锁的概念:在CPU运行过程中,不会单一的取执行一个事件,而是通过线程,或者进程来进行执行,这样CPU的利用率才得以提高,但是在不同的线程之间,由于互相独立,那么对于资源的访问来说,就可能同时进行,假如A进程获取一个临时变量temp的值,但是在获取的同时,B进程却将temp的值改变了,这时就会出现资源访问的冲突,为了更好的解决这个问题,就有了锁的概念,说的明白些,他就像现实中的锁一样,我们程序中所有的资源,包括变量,内存等都存放在一个房子里,开始时,锁处于开锁状态,如果某一个线程需要访问资源时,就需要拿到这把锁,进到房子里,把门锁上,这样就不会有其他人来干扰你,等你对资源访问结束后,在把锁打开,放下锁,这样别人就可以进入,这样就保证了对资源访问的顺序,这种锁叫互斥锁,这种机制是我们所说的避免竞争。

条件变量:条件变量是线程同步的一种机制。它给多个线程提供一个回合场所。所谓的条件变量就是需要满足这个条件,才可以继续进行操作。

互斥锁:

1.初始化:

1)动态方式

int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
mutex   出参,互斥锁
attr    互斥锁的属性,NULL表示默认/缺省的属性

2)静态的方式
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
     //一般都选择静态方式

2.加锁:

int pthread_mutex_lock(pthread_mutex_t *mutex);
给mutex互斥锁加锁
1
.互斥锁没有被锁:加锁
2
.互斥锁已经被锁:阻塞/等待,直到被解锁,然后再对mutex互斥锁加锁

3.解锁:

int pthread_mutex_unlock(pthread_mutex_t *mutex);

条件变量:

1.初始化:

动态方式:
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

静态的方式:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2.等待条件变量

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

原子性的解锁并阻塞/等待条件变量。

3.唤醒条件变量

int pthread_cond_signal(pthread_cond_t *cond);

上面的是函数的介绍,为了方便查看,接下来说一下为什么cond和mutex要配合使用。

首先:在pthread_cond_wait()函数之前,要人为获取一把锁,在pthread_cond_wait()执行时,会自动释放这个锁,并且处于等待/阻塞条件,等待信号来临,一但信号来临,那么在pthread_cond_wait()函数调用返回之前,自动将指定的互斥量重新锁住,所以必须在pthread_cond_wait()之后再人为释放锁。其结实际用法为下:

pthread_mutex_lock(&mutex);         //加锁

pthread_cond_wait(&flag,&mutex); //等待,清除标记flag

pthread_mutex_unlock(&mutex);    //解锁
其次:对于pthread_cond_signal()函数有两种用法,第一种在加锁与解锁之间,第二种是在加锁解锁之后:

pthread_mutex_lock(&mutex);

pthread_cond_signal(&flag);

pthread_mutex_unlock(&mutex);

这种方式的缺点是:在某线程中,会遭虫等待线程从内核中唤醒(cond_signal是有内核发起的),然后又回到内核空间(cond_wait返回后会有原子加锁的行为),所以这一来一回会产生性能的问题,但是在Linux下或者NPTL里面不会,因为Linux线程中有两个队列即cond_wait和cond_signal两个队列,pthread_cond_signal()只是让线程在从wait队列移动到cond队列,不会再永和空间和内核之间往返,不会有应能损耗。

pthread_mutex_lock(&mutex);

pthread_mutex_unlock(&mutex);

pthread_cond_signal(&flag);
这种方式的缺点是:如果在unlock和signal之前有一个优先级更低的线程正在等待mutex的话,那么他就会抢占高优先级的线程,而上面的情况则不会出现。

优点是:不会产生性能的损耗,因为在signal之前就已经解锁了。

cond和mutex两个组合使用是为了避免,在一个线程中,如果在wait之前,另一个函数已经完成signal了,那么这个线程将阻塞在这里,从而错过了signal,所以用mutex来实现两个进程的同步,当我等待前上锁,等待后释放锁,然后另一个线程获取锁,产生signal信号,在释放锁。

下面给出一个小程序来测试一下:

#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <ctype.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //静态,解锁状态pthread_cond_t flag = PTHREAD_COND_INITIALIZER;    //静态,置位状态int main(int argc ,char *argv[]){    pthread_t t1;    void *numWords(void *);        pthread_create(&t1,NULL,numWords,NULL);            pthread_mutex_lock(&mutex);      //加锁    pthread_cond_wait(&flag,&mutex); //等待,清除标记flag    printf("pth 1\n");    pthread_mutex_unlock(&mutex);    //解锁            return 0;}void *numWords(void *f){           pthread_mutex_lock(&mutex);    printf("pth 2\n");    pthread_mutex_unlock(&mutex);    pthread_cond_signal(&flag);            return NULL;}
在程序运行后,打印结果,pth 2 永远在pth 1之前。即两个新城通过mutex与cond的结合使其线程间同步。

如果去掉mutex

#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <ctype.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //解锁状态pthread_cond_t flag = PTHREAD_COND_INITIALIZER;    //置位状态int main(int argc ,char *argv[]){        pthread_t t1;        void *numWords(void *);        pthread_create(&t1,NULL,numWords,NULL);            pthread_cond_wait(&flag,&mutex); //等待,清除标记flag    printf("pth 1\n");            return 0;}void *numWords(void *f){    printf("pth 2\n")    pthread_cond_signal(&flag);             return NULL;}
程序在运行时,会出现阻塞情况,分线程先执行了signal即打印显示pth 2,然后程序阻塞,无法显示 pth 1,这就是为什么cond与mutex要结合使用的原因。



原创粉丝点击