16、cgminer学习之:pthread_mutex_init和pthread_cond_init

摘要:
使用者进程获取互斥锁-->进入关键区域-->发现共享资源n不满足继续执行的条件(n>0)-->等待n>0。使用者进程持有互斥锁-->生产者进程无法进入关键区域->无法修改n-->生产者等待使用者释放互斥锁以解决死锁。在生产者和消费者模型中使用互斥体和条件变量的流程图如下,其中蓝色表示消费者的执行流,红色表示生产者的执行流。

1.原理 假设有两个线程同时访问一个全局变量 n,这个全局变量的初始值等于0。

Int  n = 0 ;

         消费者线程 A 进入临界区,访问 n,A 必须等到 n 大于 0 才能接着往下执行,如果 n== 0,那么 A 将一直等待。

         还有一个生产者线程 B,B 进入临界区,修改 n 的值,使得 n >0,当 n > 0 时,B 通知等待 n > 0 的消费者线程A。A 被 B 通知之后就可以接着往下执行了。

 16、cgminer学习之:pthread_mutex_init和pthread_cond_init第1张

         以上情况造成死锁:

         当 A 进入临界区时,其他线程不能进入临界区,意味着 B 没有机会去修改 n, n 的值一直为 0,不满足A 继续执行的条件(n > 0),A 只能一直等待。

         消费者进程拿到互斥锁 --> 进入临界区 --> 发现共享资源 n 不满足继续执行的条件(n> 0) --> 等待 n > 0

         消费者进程占有互斥锁 --> 生产者进程无法进入临界区 --> 无法修改 n 的值 --> 生产者等待消费者释放互斥锁

         解决死锁的方案就是采用条件变量。

         通常情况下,对共享资源(比如 n)保护要用到锁操作,当一个进程进入临界区时会拿到互斥锁(lock 操作),然后其他进程拿不到互斥锁,也就无法进入临界区,因此当进程进入临界区,发现共享资源不满足继续向下执行的条件(n > 0)时,就应该释放锁,让其他进程修改共享资源,以满足自己所需的执行条件。

消费者进入临界区 --> 共享变量不满足继续向下执行的条件 --> 消费者等待在条件变量 --> 释放互斥锁 --> 生产者进入临界区 --> 修改条件变量 --> 生产者通知消费者:现在有多的资源了,快来使用 --> 消费者再次拿互斥锁 --> 消费资源 --> 释放互斥锁。如果有多个消费者进程等待在条件变量上,就可以形成等待队列。

生产者和消费者模型中互斥锁和条件变量的使用流程图如下,其中蓝色代表消费者的执行流,红色是生产者的执行流。

16、cgminer学习之:pthread_mutex_init和pthread_cond_init第2张

2.使用方法
         条件变量的使用主要有以下五个函数:

/* 初始化一个条件变量 */
int pthread_cond_init (pthread_cond_t* cond, pthread_condattr_t *cond_attr);

/* 销毁一个条件变量 */
int pthread_cond_destroy(pthread_cond_t* cond);

/* 令一个消费者等待在条件变量上 */
int pthread_cond_destroy(pthread_cond_t* cond);

/* 生产者通知等待在条件变量上的消费者 */
int pthread_cond_signal(pthread_cond_t* cond);

/* 生产者向消费者广播消息 */
int pthread_cond_broadcast(pthread_cond_t* cond);


        

消费者等待条件的伪代码:

pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
while( 条件为假)
pthread_cond_wait(cond, mutex); // 令进程等待在条件变量上
修改条件
pthread_mutex_unlock(&mutex); // 释放互斥锁


 

生产者通知消费者的伪代码:

pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区
设置条件为真
pthread_cond_signal(cond); // 通知等待在条件变量上的消费者
pthread_mutex_unlock(&mutex); // 释放互斥锁


 

以下是示例程序,演示了互斥锁和条件变量配合使用方法,由于是在Linux下写的程序,所以注释全是英文的。

condition_test.c:

/***************************************************************
* Copyright (C) 2016 chengonghao
* All rights reserved.
*
* chengonghao@yeah.net
***************************************************************/
#include <unistd.h>
#include <pthread.h>

#define CONSUMERS_COUNT 2
#define PRODUCERS_COUNT 1

pthread_mutex_t g_mutex ;
pthread_cond_t g_cond ;

pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT] ;
int share_variable = 0 ;// this is the share variable, shared by consumer and producer

void* consumer( void* arg )
{
int num = (int)arg ;
while ( 1 )
{
/******* critical section begin *******/
pthread_mutex_lock( &g_mutex ) ;

// if share_variable == 0, means consumer shell stop here
while ( share_variable == 0 )
{
printf( "consumer %d begin wait a condition... ", num ) ;
// put a thread blocked ont a condition variable( here is g_cond),
// and unlock the mutex( here is g_mutex )
pthread_cond_wait( &g_cond, &g_mutex ) ;
}
// here means n != 0 and consumer can goes on
// consumer consumed shared variable, so the number of shared variable shell minus
printf( "consumer %d end wait a condition... ", num ) ;
printf( "consumer %d begin consume product ", num ) ;
-- share_variable ;

pthread_mutex_unlock( &g_mutex ) ;
/******** critial section end *********/
sleep( 1 ) ;
}

return NULL ;
}

void* producer( void* arg )
{
int num = (int)arg ;
while ( 1 )
{
/******* critical section begin *******/
pthread_mutex_lock( &g_mutex ) ;

// produce a shared variable
printf( "producer %d begin produce product... ", num ) ;
++ share_variable ;
printf( "producer %d end produce product... ", num ) ;
// unblock threads blocked on a condition variable( here is g_cond )
pthread_cond_signal( &g_cond ) ;
printf( "producer %d notified consumer by condition variable... ", num ) ;
pthread_mutex_unlock( &g_mutex ) ;

/******** critial section end *********/
sleep( 5 ) ;
}

return 1 ;
}


int main( void )
{
// initiate mutex
pthread_mutex_init( &g_mutex, NULL ) ;
// initiate condition
pthread_cond_init( &g_cond, NULL ) ;

// initiate consumer threads
for ( int i = 0; i < CONSUMERS_COUNT; ++ i )
{
pthread_create( &g_thread[i], NULL, consumer, (void*)i ) ;
}
sleep( 1 ) ;
// initiate producer threads
for ( int i = 0; i < PRODUCERS_COUNT; ++ i )
{
pthread_create( &g_thread[i], NULL, producer, (void*)i ) ;
}
for ( int i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++ i )
{
pthread_join( g_thread[i], NULL ) ;
}

pthread_mutex_destroy( &g_mutex ) ;
pthread_cond_destroy( &g_cond ) ;
}


 

编译程序:

cgh@ubuntu:~/condition_test$ gcc condition_test.c -o test –lpthread


运行程序:

1.      第一个框,消费者 1 和0 发现share_variable == 0,于是先后等待在条件变量上;

2.      第二个框,生产者 0 开始生产共享变量,即 ++ share_variable,然后通知等待在条件变量上的消费者;

3.      第三个框,消费者 1 被生产者唤醒,开始消费共享变量,即– share_variable;

4.      第四个框,生产者 0 继续生产共享变量,++ share_variable,然后通知等待在条件变量上的消费者;

5.      第五个框,消费者 0 被唤醒,开始消费共享变量,即– share_variable;

以此类推,以上描述简化了拿锁和释放锁的过程,可以结合上面的流程图来理解代码。
---------------------
作者:chengonghao
来源:CSDN
原文:https://blog.csdn.net/chengonghao/article/details/51779279
版权声明:本文为博主原创文章,转载请附上博文链接!

免责声明:文章转载自《16、cgminer学习之:pthread_mutex_init和pthread_cond_init》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇logicaldoc的外部认证——AD集成程序员修炼之道阅读笔记02下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

pthread_exit/pthread_kill之后局部对象之析构

一、多线程与析构函数这个是在C++编码中可能存在的一个问题,假设说一个线程执行了局部变量的构造函数之后,没有退出局部对象作用域之前,它主动退出线程(pthread_exit)或者被动退出线程(pthread_kill ed),那么这个局部变量的析构函数是否会执行?这个问题对于通常的程序来说影响并不大,但是对于某些依赖在析构函数中执行复杂的系统级对象操作来说...

软考--操作系统知识--PV操作

1.任何两个并发进程之间存在着( D)的关系。 A.各自完全独立 B.拥有共享变量 C.必须互斥 D.可能相互制约 2.并发进程执行的相对速度是(D )。 A.由进程的程序结构决定的 B.由进程自己来控制的 C.在进程被创建时确定的 D.与进程调度策略有关的 3.并发进程执行时可能会出现“与时间有关的错误”,这种错误是由于并发进程(A )引起的。...

Linux平台用C++实现事件对象,同步线程

前文在Win32平台上用C++实现了事件对象Event,对线程进行同步,以达到期望目的。这次在Linux平台上实现与之类似的事件对象。与其相关的一组API包括:pthread_mutex_init,pthread_cond_init,pthread_mutex_lock,pthread_cond_wait,pthread_mutex_unlock,pthr...

浅谈 linux 多线程编程和 windows 多线程编程的异同

原文:http://software.intel.com/zh-cn/blogs/2011/03/24/linux-windows/ 很早以前就想写写linux下多线程编程和windows下的多线程编程了,但是每当写时又不知道从哪个地方写起,怎样把自己知道的东西都写出来,下面我就谈谈linux多线程及线程同步,并将它和windows的多线程进行比较,看看他...

pthread实现多线程查询(转)

导读:大多数网站的性能瓶颈不在PHP服务器上,因为它可以简单地通过横向增加服务器或CPU核数来轻松应对(对于各种云主机,增加VPS或CPU核数就更方便了,直接以备份镜像增加VPS,连操作系统、环境都不用安装配置),而是在于MySQL数据库。如果用 NoSQL 数据库,也许需要十次查询,才能处理完同样地业务逻辑。此时PHP多线程的作用非常明显,它可以同时执行...

线程的查看以及利用gdb调试多线程

摘自:https://blog.csdn.net/zhangye3017/article/details/80382496 1. 线程的查看首先创建两个线程: 1 #include <stdio.h> 2 #include <unistd.h> 3 #include <pthread.h> 4 #include...