互斥锁和条件变量(1)

*********************************


互斥锁和条件变量相结合实现生产者及消费者模型

 

一、线程的创建

    

Linux系统的线程创建函数使用pthread_create

原型:

 #include <pthread.h>

 

  int pthread_create(pthread_t  *restrict   thread_id,

                 const   pthread_attr_t  * restrict attr,

                 void * (*start_routine)(void *),

                 void * restrict   arg ); 

   

第一个参数线程创建成功后得到线程idthread_idpthread_t *类型)。

第二个参数是需要设置线程的属性,包括线程栈大小等信息,attrpthread_attr_t*)。如果不关心,设置NULL

第三个参数是线程执行的函数,类型如void * (*start_routine)(void *)

第四个参数为start_routine执行函数的传入参数,如果没有要传入的数据,设置为NULL

 

二、互斥锁

1.互斥锁的创建、初始化及销毁方式

互斥锁的初始化的有静态和动态两种。

1)静态初始化其实跟一般的变量初始化差不多,

POSIX定义了一个宏PTHREAD_MUTEX_INITIALIZER来静态初始化互斥锁,方法如下:

              pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;

  

采用PTHREAD_MUTEX_INITIALIZER初始化,必须在定义的初始化,这是因为在 pthread.h 中, 

PTHREAD_MUTEX_INITIALIZER 

定义为:


#define PTHREAD_MUTEX_INITIALIZER \
    { { 0, 0, 0, 0, 0, 0, { 0, 0 } } }

 

 

当然,也可以通过调用函数pthread_mutex_init来初始化。

原型:

#include <pthread.h>

  int  pthread_mutex_init(pthread_mutex_t * restrict mutex,

 const  pthread_mutexattr_t * restrict attr );

 

使用函数初始化,按默认方式:

pthread_mutex_t mutex ;  

pthread_mutex_init( &mutex, NULL );

 

(2)互斥锁的动态创建及初始化方法

 

动态创建,定义为指针变量。

如下:

pthread_mutex_t   *pMutex  = NULL;

pMutex =(pthread_mutex_t   * )  malloc( sizeof(pthread_mutex_t  ) ) ;  

 

pthread_mutex_init(pMutex , NULL );

 

需要申请内存。销毁之后要记得释放内存,不然会内存泄漏。

同时程序或者模块结束时互斥锁要记得销毁,不然是资源泄漏

 

(3)互斥锁的销毁方法

 销毁函数为:

  int   pthread_mutex_destroy(  pthread_mutex_t  * mutex );

                

2.互斥锁的使用

(1)加锁函数

   int   pthread_mutex_lock(pthread_mutex_t *  mutex);

   int   pthread_mutex_trylock(pthread_mutex_t * mutex);

 

注意:pthread_mutex_trylock执行成功,返回0 的话,以为着已经成功加锁。

(2)解锁函数

     int    pthread_mutex_unlock(  pthread_mutex_t  *  mutex  );

   

 (3)互斥操作

 

pthread_mutex_lock()

...

Do Something Work

...

pthread_mutex_unlock()

 

需要的注意的地方,加锁之后,未解锁之前,其他线程请求加锁时,会进入阻塞状态,直到这边解锁为止。

 

因此,任何地方加锁,在返回的时候的要记得解锁,不然进程就死锁了。


原则上,谁加锁,谁就来解锁。

 

3.死锁的产生及解决

1任何地方线程加锁,在返回的时候的要记得解锁,不然进程中如果其他线程申请加锁的时候就永远阻塞了,这就造成了死锁了。

2)两个锁以上的情况。以不同的线程以相反的顺序加锁,很容易造成死锁。

3)同个线程在加锁成功后,未解锁的情况下,重新申请加锁。


三、条件变量

1.条件变量的初始化及销毁

(1)条件变量的静态初始化

        pthread_cond_t   cond = PTHREAD_COND_INITIALIZER ;(静态方法)

         或者调用函数pthread_cond_init初始化。(常用)

            原型: int   pthread_cond_init( pthread_cond_t  * restrict cond,

                   const  pthread_condattr_t  * restrict  attr) ;  

              例子:

              pthread_cond_t   cond;

              pthread_cond_init(&cond, NULL); (默认NULL

(2)条件变量的动态初始化

            pthread_cond_t  * pCond;

            pCond = (pthread_cond_t  *)malloc(  sizeof(pthread_cond_t ) );

            pthread_cond_init(pCond , NULL);

(3)条件变量的销毁

销毁函数:

    int   pthread_cond_destroy(   pthread_cond_t  *cond  );

注意:如果是销毁动态的条件变量,销毁后需要释放内存。

模块终结时,也必须销毁条件变量,不然也是资源泄漏。

 

另外该函数要配合pthread_cond_broadcast使用,不然是无法destroy成功的。


2.条件变量的使用

(1)条件等待函数

pthread_cond_timedwait限时等待,超时返回ETIMEDOUT

 int       pthread_cond_timedwait(   pthread_cond_t *restrict cond,
     pthread_mutex_t *restrict mutex,

     const struct timespec *restrict abstime);


pthread_cond_wait无限时等待

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

(2)条件激活函数

    #include <pthread.h>

pthread_cond_broadcast激活所有挂起的等待

       int pthread_cond_broadcast(pthread_cond_t *cond);


pthread_cond_signal只激活一个

       int pthread_cond_signal(pthread_cond_t *cond);

3.条件变量的应用


 条件变量即跟条件的有关系。设定条件判断,如 if ( x < y )时,进入条件等待,线程挂起(pthread_cond_wait或pthread_cond_timedwait),等待条件不满足时,唤醒线程。也就是说,当if  (x  >= y )时,由另外线程调用

条件激活函数pthread_cond_signal (或pthread_cond_broadcast)去激活挂起的线程。

换句话来说,挂起的线程就等着条件if  (x  >= y )满足。

因此,条件变量的好处是避免了死锁和竞争的问题,提高了cpu的效率。


pthread_cond_wait(或pthread_cond_timedwait)需要结合互斥锁使用

如下:


pthread_mutex_lock(&mutex);

        if ( x < y )

                pthread_cond_wait(&cond, &mutex);

       ...

      do something work

      pthread_mutex_unlock(&mutex);

       

pthread_cond_wait需要传条件变量和互斥锁进去,当进入该函数,会先解锁mutex,然后线程加入等待唤醒队列,当被唤醒时,会重新对mutex进行加锁,线程起来。

因此加锁和解锁要保持一致。


pthread_cond_signal 只激活一个条件变量挂起的线程。pthread_cond_signal 的使用,可以加锁也可以不加。

pthread_cond_broadcast去激活一个条件变量相关的所有挂起的线程

 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值