• 前一篇讲了用消息队列实现信号量，这里使用条件变量实现信号量。有关条件变量的使用可以参考我的一篇博文。其实现原理和前面的两篇文章说述的有很大的不同。  其原理是通过一个变量sig_num来标明信号量的值(即资源...

前一篇讲了用消息队列实现信号量，这里使用条件变量实现信号量。有关条件变量的使用可以参考我的一篇博文。其实现原理和前面的两篇文章说述的有很大的不同。

还是上代码吧。

#ifndef COND_SEM_HPP
#define COND_SEM_HPP

#include"cond_sync.hpp"
#include  <errno.h>

typedef Cond_sync_t cond_sem_t;

#define COND_SEM_INITIALIZER(num) COND_SYNC_INITIALIZER_V(num)

inline int cond_sem_init(cond_sem_t* con, int num)
{
int status = cond_sync_init(con);
con->sig_num = num;
return status;
}

inline int cond_sem_p(cond_sem_t* con)
{
return cond_sync_wait(con);
}

inline int cond_sem_tryP(cond_sem_t* con)
{
int status = cond_sync_timedwait(con, 0);
if( status == ETIMEDOUT )
return EAGAIN;

return status;
}

inline int cond_sem_v(cond_sem_t* con)
{
return cond_sync_signal(con);
}

inline int cond_sem_destroy(cond_sem_t* con)
{
return cond_sync_destroy(con);
}

#endif // COND_SEM_HPP

如代码所示，cond_sem_t是由Cond_sync_t实现的。

cond_sync.hpp文件

#ifndef COND_SYNC_HPP
#define COND_SYNC_HPP

typedef struct Cond_sync_tag
{
int sig_num; //signal's num
int valid;
}Cond_sync_t;

#define COND_SYNC_VALID 0xabcd

#define COND_SYNC_INITIALIZER_V(num) \

#define COND_SYNC_INITIALIZER COND_SYNC_INITIALIZER_V(0)

int cond_sync_init(Cond_sync_t* cond_s);
int cond_sync_destroy(Cond_sync_t* cond_s);
int cond_sync_wait(Cond_sync_t* cond_s);
int cond_sync_timedwait(Cond_sync_t* cond_s, int msecs); //Millisecond
int cond_sync_signal(Cond_sync_t* cond_s);

#endif // COND_SYNC_HPP

cond_sync.cpp文件
#include"cond_sync.hpp"
#include<sys/time.h>
#include<errno.h>

int cond_sync_init(Cond_sync_t* cond_s)
{
int status;
if( status != 0 )
goto error;

if( status != 0 )
{
goto error;
}
cond_s->sig_num = 0;
cond_s->valid = COND_SYNC_VALID;

return 0;

error:
return status;
}

int cond_sync_destroy(Cond_sync_t* cond_s)
{
int status1, status2;

if( cond_s == NULL || cond_s->valid != COND_SYNC_VALID )
return EINVAL;

cond_s->valid = 0;
//try best to destroy all object, so judge the status' after all
//object destroy

if( status1 != 0 )
return status1;

return status2;
}

void cleanup_unlock(void* arg)
{
}

int cond_sync_wait(Cond_sync_t* cond_s)
{
int status;

if( cond_s == NULL || cond_s->valid != COND_SYNC_VALID )
return EINVAL;

if( status != 0 )
return status;

//睡眠的线程将苏醒，然后继续锁住mutex, 之后就退出终止。
//所以，要设定一个清理函数，发生这种情况时，在清理函数中解锁。

while( cond_s->sig_num <= 0)
{
//cann't be interruptted by a signal
if( status != 0 )
{
break;
}
}

--cond_s->sig_num; //可用资源减一

//ignore the error. if status == 0 and unlock return not 0.
//we cann't return this message to user. it will confuse the user
//the signal is sucessful, but return error code

return status;
}

int cond_sync_timedwait(Cond_sync_t* cond_s, int msecs) //Millisecond
{
struct timeval now;
struct timespec waittime;
int status;
int sec;

if( cond_s == NULL || cond_s->valid != COND_SYNC_VALID )
return EINVAL;

if( msecs < 0 )
msecs = 0;

sec = msecs / 1000;
gettimeofday(&now, NULL);
waittime.tv_sec = now.tv_sec + sec;
waittime.tv_nsec = (now.tv_usec + (msecs%1000)*1000)*1000;

if( status != 0 )
return status;

while( cond_s->sig_num <= 0 )
{
if( status == EINTR ) //can be interruptted by a signal.
continue;
else
break;
}

if( status == 0 )
--cond_s->sig_num;

//ignore the error. if status == 0 and unlock return not 0.
//we cann't return this message to user. it will confuse the user
//the signal is sucessful, but return error code

return status;
}

int cond_sync_signal(Cond_sync_t* cond_s)
{
int status;

if( cond_s == NULL || cond_s->valid != COND_SYNC_VALID )
return EINVAL;

if( status != 0 )
goto error;

++cond_s->sig_num; //加一，表示可用资源多了一个
if( status != 0 )
goto error;

error:
return status;
}

测试代码和前面的两个差不多。

#include "cond_sem.hpp"
#include  <stdio.h>
#include  <string.h>
#include  <sys/types.h>
#include  <fcntl.h>
#include  <stdlib.h>
#include  <unistd.h>
#include  <errno.h>

#define	NBUFF	 8
#define BUFFSIZE 4096

struct {	/* data shared by producer and consumer */
struct {
char	data[BUFFSIZE];			/* a buffer */
ssize_t	n;						/* count of #bytes in the buffer */
} buff[NBUFF];					/* NBUFF of these buffers/counts */
cond_sem_t nempty, nfull;		/* semaphores, not pointers */
} shared;

int writer_index = 0, reader_index = 0;

int		fd;							/* input file to copy to stdout */
void* produce(void *), *consume(void *);
void* produce_tryP(void *arg);

int main(int argc, char **argv)
{

if (argc != 2)
{
printf("use <pathname> as pramater \n");
exit(1);
}

fd = open(argv[1], O_RDONLY);
if( fd == -1 )
{
printf("cann't open the file\n");
return -1;
}

cond_sem_init(&shared.writer_mutex, 1);
cond_sem_init(&shared.nempty, NBUFF);
cond_sem_init(&shared.nfull, 0);

cond_sem_destroy(&shared.writer_mutex);
cond_sem_destroy(&shared.nempty);
cond_sem_destroy(&shared.nfull);

exit(0);
}

void *produce(void *arg)
{
while( 1 )
{
cond_sem_p(&shared.nempty);	/* wait for at least 1 empty slot */

cond_sem_p(&shared.writer_mutex);

shared.buff[writer_index].n =

if( shared.buff[writer_index].n == 0 )
{
cond_sem_v(&shared.nfull);
cond_sem_v(&shared.writer_mutex);
return NULL;
}

writer_index = (writer_index+1)%NBUFF;

cond_sem_v(&shared.nfull);
cond_sem_v(&shared.writer_mutex);
}

return NULL;
}

void* produce_tryP(void *arg)
{
int status;
while( 1 )
{
/* wait for at least 1 empty slot */
while( 1 )
{
status = cond_sem_tryP(&shared.nempty);
if( status == 0 )
break;
else if( status == EAGAIN )
{
usleep(10*1000); //sleep 10 毫秒
continue;
}
else
return NULL;
}

cond_sem_p(&shared.writer_mutex);

shared.buff[writer_index].n =

if( shared.buff[writer_index].n == 0 )
{
cond_sem_v(&shared.nfull);
cond_sem_v(&shared.writer_mutex);
return NULL;
}

writer_index = (writer_index+1)%NBUFF;

cond_sem_v(&shared.nfull);
cond_sem_v(&shared.writer_mutex);
}

return NULL;
}

void* consume(void *arg)
{
while( 1 )
{
cond_sem_p(&shared.nfull);

{
cond_sem_v(&shared.nempty);
return NULL;
}

cond_sem_v(&shared.nempty);
}

return NULL;
}

测试结果：


展开全文
• 一些重要的点 首先 unique_lock是在作用域内有效 默认一开始是加锁的了 条件变量 我的理解是 先对unique_lock 解锁，然后根据条件，如果（匿名函数写法）条件为真，那么获得锁，否则等待通知接着竞争锁，
#include<iostream>
#include<mutex>
#include<condition_variable>
using namespace std;
class semaphere{
public:
semaphere(int n):m_count(n){}
semaphere(const semaphere& s)=delete;
semaphere & operator=(const semaphere& s)=delete;
void Wait(){
unique_lock<mutex> lc(m_mtx);
m_cv.wait(lc,[&]{return m_count>0;});
m_count--;..
}
void Signal(){
{
unique_lock<mutex> lc(m_mtx);
m_count++;
}
m_cv.notify_all();
}
private:
mutex m_mtx;
condition_variable m_cv;
int m_count;
};


一些重要的点
首先 unique_lock是在作用域内有效 默认一开始是加锁的了
条件变量 我的理解是 先对unique_lock 解锁，然后根据条件，如果（匿名函数写法）条件为真，那么获得锁，否则等待通知接着竞争锁，


展开全文
• 在某些平台，信号量可能并不支持，可以使用互斥锁和条件变量模拟实现信号量，代码如下 代码 typedef struct { int val; //信号量的值 pthread_mutex_t mutex; pthread_cond_t cond; } semaphore_t; inline...
说明
在某些平台，信号量可能并不支持，可以使用互斥锁和条件变量模拟实现信号量，代码如下

代码
typedef struct {
int val;	//信号量的值
} semaphore_t;

inline void sem_init(semaphore_t *s, int n)
{
s->val = n;
}

inline void sem_post(semaphore_t *s)
{
s->val++;
}

inline int sem_wait(semaphore_t *s)
{
int rc = 0;
while (s->val == 0)
s->val--;
return rc;
}

inline void sem_destroy(semaphore_t *s)
{
s->val = 0;
}
展开全文
接着上一篇，继续讨论如何利用pthread_cond_t来实现sem_t。目前的Linux内核都支持信号量sem_t，但也有一些老的OS，如AIX4，和早期的Solaris并不支持信号量，毕竟semaphore这个东东并没有包括在POSIX标准里。这种情况下有必要利用pthread_mutex_t + pthread_cond_t来模拟semaphore啦。（什么？pthread_mutex_t pthread_cond_t也不支持？ ！@#￥%！）

其实实现起来真的很简单，

class Semaphore {
protected:
unsigned int waiters;

public:
Semaphore();
virtual ~Semaphore() {}
int p();
int v();
}

Semaphore::Semaphore() {
waiters = 0;
}

int Semaphore::p() {
while (waiters <= 0) {
}
waiters--;
}

int Semaphore::v() {
waiters++;
if (waiters > 0) {
}
}

展开全文
• ## 条件变量和信号量

千次阅读 2019-08-08 14:57:30
1、条件变量 条件变量(condition variable)是利用线程间共享的全局变量进行同步的一种机制，主要包括两个...2、windows条件变量实现 （1）利用同步对象实现条件变量 自己封装的一个条件变量： 1 #ifndef _M...
• 生产者消费者问题C语言实现： 互斥锁和条件变量实现 互斥锁和同步信号量实现
• 线程安全概念 线程安全的概念就是多个执行流对临界资源进行争抢访问但是不会出现数据二义性。...我们通过互斥锁，条件变量信号量实现同步与互斥，下面对其逐一介绍。 互斥锁 条件变量 信号量 ...
• 互斥锁、条件变量信号量是系统为实现多线程（多进程）访问共享资源或共同协作的同步机制
• 以前读过，最近才感觉它是在 利用POSIX互斥锁和条件变量实现POSIX的信号量。 在《Unix网络编程 卷二进程间通信》中有用System V模拟 POSIX信号量的论述。 LwIP是一个轻型TCP/IP协议栈，它利用操作系统模拟层实现了...
• 条件变量实现如下： #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> //节点结构体 struct msg { int num; //数据区 struct msg *next; //链表区 }; ...
• 生产者与消费者模型 一个场所，两种模型，三种关系 场所：线程安全的队列 模型：生产者、消费者 关系：生产者与生产者之间（互斥）、生产者与消费者（同步与...使用条件变量实现生产者消费者模型 // 使用条...
• 首先第一个区别条件变量有广播的功能，所以当实现订阅的时候，需要广播事件的时候必须使用条件变量，而semaphore只能出发一个订阅 有人这么说： Conditional variable is essentially a wait-queue, that supports...
• 面试的时候经常被问到互斥量，条件...如面试官所说，信号量可以实现互斥量，大部分情况下也可以实现条件变量。甚至使用信号量实现远比其他实现更容易理解。然而很多时候使用信号量替换条件变量的可能会降低系统性能
• 使用互斥条件变量实现生产者消费者模型（串行） #include #include #include #include /* * 使用互斥条件变量实现生产者消费者模型 */ typedef struct node { int data; struct node* next; }Node; //永远...
• 在我们对一些全局变量的进行非原子性操作的时候就可能出现非线程安全，比如我们吃面的问题。 我们做面的人就是生产者，吃面的人就是我们的消费者，当我们的消费者需要吃面的时候就唤醒我们的生产者进行生产，当我们...
• 条件变量与互斥锁一样，都是一种数据变量，这两者通常搭配起来使用。 条件变量的作用： 实现线程的同步与互斥： 接口：
• 条件变量 　使用互斥锁来实现线程间...而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足，它常和互斥锁一起使用。使用时，条件变量被用来阻塞一个线程，当条件不满足时，线程往往...
• 条件变量（Condition Variable）实现信号量（Semaphore）， 主要是通过条件变量控制资源数的加减操作，在这里定义sem_t 为  struct sem{  int num;  pthread_mutex_t lock;  pthread_cond_t cond;     }...
• 学习环境 ：　Centos6.5 Linux 内核 2.6 ...【完成】 地址：【Linux】线程总结：初识、创建、等待、终止、分离第二部分主要介绍在多线程环境下，使用同步与互斥保护共享资源，有互斥锁，条件变量信号量，以及读写锁。

...