您的位置:首页 > 编程语言

线程同步之信号量,代码实现方法2(条件变量+mutex互斥量)

2016-07-08 21:55 411 查看
方法1使用了系统semaphore,经过封装完成了信号量的实现,

本文章为方法2,使用条件变量 + 系统互斥量mutex实现信号量semaphore,代码如下所示:

//semaphore.h
#ifndef _SEMAPHORE_2_H__
#define _SEMAPHORE_2_H__

#include <pthread.h>

using namespace std;
typedef unsigned int uint32_t;

struct internal
{
pthread_condattr_t m_condattr;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
int m_count;
};
/// \class CSemaphore 信号量类

class CSemaphore {
private:
CSemaphore(CSemaphore const&);
CSemaphore& operator=(CSemaphore const&);
public:
/// 构造函数,创建系统信号量,initCnt表示信号量的初始计数
explicit CSemaphore(int initCnt = 0);

/// 析构函数,销毁系统信号量
~CSemaphore();

/// 消费信号量,当信号量为0时线程再消费信号量,线程就会被阻塞,进入信号量等待队列的队尾
/// \return pend操作后当前信号量计数
int pend();

/// 生产信号量,如果信号量为0时有线程生产信号量,会唤醒信号量其等待队列的第一个线程
/// \return post操作后当前信号量计数
int post();

/// 消费信号量,当信号量为0时线程再消费信号量,线程就会被阻塞,直到超时(毫秒)
/// \return >=0表示当前信号量计数,-1:表示超时
int pend(uint32_t timeout);

/// 尝试减少信号量,如果信号量已经为0则马上返回
/// \return 0:信号量减少成功,-1:信号量减少失败
int tryPend();

private:
struct internal* m_internal;
};//class CSemaphore

#endif
//semaphore.cpp
#include "semaphore.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>

#define PRINT_LINE_INFO \
do {\
printf("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__);\
}while(0);

#define ATTR 	m_internal->m_condattr
#define MUTEX 	m_internal->m_mutex
#define COND 	m_internal->m_cond
#define COUNT 	m_internal->m_count

CSemaphore::CSemaphore(int initCnt)
:m_internal(new struct internal)
{
PRINT_LINE_INFO;
pthread_condattr_init(&ATTR);
pthread_condattr_setclock(&ATTR, CLOCK_MONOTONIC);
/*init a condition-variable to its default value*/
pthread_cond_init(&COND, &ATTR);
/*init a condition-variable*/
pthread_mutex_init(&MUTEX, NULL);
COUNT = initCnt;
}

CSemaphore::~CSemaphore()
{
PRINT_LINE_INFO;
pthread_mutex_destroy(&MUTEX);
pthread_cond_destroy(&COND);
delete m_internal, m_internal = NULL;
}

int CSemaphore::pend()
{
PRINT_LINE_INFO;
int ret = 0;
pthread_mutex_lock(&MUTEX);
while (COUNT == 0 && ret == 0)
{
PRINT_LINE_INFO;
ret = pthread_cond_wait(&COND, &MUTEX);
}
if (ret != 0)
{
return -1;
}
COUNT = COUNT - 1;
int cnt = COUNT;
ret = pthread_mutex_unlock (&MUTEX);

return (ret == 0) ? cnt : -1;
}

int CSemaphore::post()
{
PRINT_LINE_INFO;
int ret = 0;
pthread_mutex_lock(&MUTEX);
pthread_cond_signal(&COND);
COUNT = COUNT + 1;
int cnt = COUNT;
ret = pthread_mutex_unlock(&MUTEX);

return (ret == 0) ? cnt : -1;
}

int CSemaphore::pend(uint32_t timeout)
{
PRINT_LINE_INFO;
int err = 0;
struct timespec to={0};
struct timespec now={0};
if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
{
fprintf (stderr, "clock_gettime failed, errno=%d, strerror=%s\n", errno, strerror(errno));
return -1;
}

to.tv_sec = now.tv_sec + (now.tv_nsec + (timeout%1000L)*1000000L)/1000000000L + timeout/1000L;
to.tv_nsec = (now.tv_nsec + (timeout % 1000L) * 1000000L) % 1000000000L;

pthread_mutex_lock(&MUTEX);
//超时时err != 0,此时while退出循环
while (COUNT == 0 && 0 == err)
{
PRINT_LINE_INFO;
err = pthread_cond_timedwait(&COND, &MUTEX, &to);
}
if (0 == err)
--COUNT;
int cnt = COUNT;
pthread_mutex_unlock(&MUTEX);

return (err == 0) ? cnt : -1;
}

int CSemaphore::tryPend()
{
PRINT_LINE_INFO;
int ret = -1;
ret = pthread_mutex_trylock(&MUTEX);
bool bzero = false; //可以加解锁,但是资源为0
if (ret == 0)
{
if (COUNT > 0) {
COUNT--;
bzero = false;
} else {
bzero = true;
}
ret = pthread_mutex_unlock (&MUTEX);
}
//资源为0,即使解锁成为也返回-1
ret = bzero ? -1 : ret;

return (ret == 0) ? 0 : -1;
}

int main()
{
CSemaphore sem(0);
sem.pend(10 * 1000);
sem.pend();
}


最后的测试结果:



(完)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: