在程序中,参考了SAFMQ中对事件进行封装用的信号量,但是有个地方触发了事件,但是另外一个地方没有激活,导致程序挂掉。所以自己另写了一个自定义的信号量,并编写程序进行测试。是OK的啊
先谈谈应用场景,信号量用很多,比如计数信号量,互斥信号量等等,我在此处主要还是用来在线程间同步用的。
一个线程获取数据(RecvMsgThread),一个线程存放数据(SendMsgThread)。但是数据中心中并不一定有数据,所以此处该线程就会阻塞,直至存放数据线程将数据放到数据中心中,并释放信号量,这样获取线程被激活,可以继续获取数据,其实就这么一个简单的应用场景。
看看信号量是如何封装的:
#ifndef _CSIGNAL_H
#define _CSIGNAL_H
class _declspec(dllexport) CSignal
{
public:
enum Result { SIGNAL_TIMEOUT, SIGNAL_SET, SIGNAL_ERROR };
CSignal();
~CSignal();
CSignal::Result WaitForSignal(long waitMilSecs);
void ReleaseSignal();
private:
HANDLE m_customSignal;
};
#endif
#include "stdafx.h"
#include "CustomSignal.h"
CSignal::CSignal()
{
m_customSignal = CreateSemaphore(
NULL, // 默认安全属性
0, // 初始化计数器
1, // 最大计数
NULL); // 未命名
};
CSignal::~CSignal()
{
CloseHandle(m_customSignal);
};
CSignal::Result CSignal::WaitForSignal(long waitMilSecs)
{
DWORD result;
if (waitMilSecs < 0)
result = ::WaitForSingleObject(m_customSignal, INFINITE);//表示一直等待
else
result = ::WaitForSingleObject(m_customSignal, waitMilSecs);
if (result == WAIT_OBJECT_0) //事件收到通知
return CSignal::SIGNAL_SET;
else if (result == WAIT_TIMEOUT) //事件未收到通知,超时
return CSignal::SIGNAL_TIMEOUT;
return CSignal::SIGNAL_ERROR;
};
void CSignal::ReleaseSignal()
{
ReleaseSemaphore(m_customSignal,// 信号量句柄
1, // 释放后计数器减1
NULL ); // 获得计数
}
在看看我是如何测试的。
首先要有两个线程都访问的数据中心,定义如下:
#ifndef _DATA_SOURCE_H
#define _DATA_SOURCE_H
#include <vector>
#include "../COMMUtil/Mutex.h"
#include "../COMMUtil/Signal.h"
#include "../COMMUtil/CustomSignal.h"
#include <iostream>
using namespace std;
class DataSource
{
public:
int m_nDataLen;
vector<int> dataSource;
Mutex m_mutex; //对资源进行互斥
CSignal m_signal; //没有资源阻塞,有资源提醒
//产生数据
void ProduceData(int nInputData)
{
MutexLock mutexLock(&m_mutex);
dataSource.push_back(nInputData);
m_signal.ReleaseSignal();
cout<<"DataSource: ProduceData: ReleaseSignal"<<endl;
};
void ConsumeData(int& nOutputData)
{
MutexLock mutexLock(&m_mutex);
if (dataSource.empty())
{
CSignal::Result ret = m_signal.WaitForSignal(5*1000);
if (ret == CSignal::SIGNAL_SET)
cout<<"DataSource: ConsumerData: Signal Released"<<endl;
}
if (dataSource.size() > 0)
{
vector<int>::iterator iter = dataSource.begin();
nOutputData = *iter;
dataSource.erase(iter);
cout<<"Consumer: "<<nOutputData<<endl;
}
};
};
#endif
发送数据线程定义如下:
#pragma once
#include "../COMMUtil/Thread.h"
#include <vector>
#include "DataSource.h"
using namespace std;
class SendMsgThread :public Thread
{
private:
DataSource* m_pDataSource;
public:
SendMsgThread(void);
SendMsgThread(DataSource* pDataSource);
~SendMsgThread(void);
protected:
void *run();
};
SendMsgThread::SendMsgThread(DataSource* pDataSource)
{
m_pDataSource = pDataSource;
}
void * SendMsgThread::run()
{
cout<<"SendMsgThread...................."<<endl;
for (int i = 0; i < 1000000; i++)
{
Sleep(2*100);
m_pDataSource->ProduceData(i);
}
return NULL;
}
接收数据线程定义:
//接收数据线程
#pragma once
#include "../COMMUtil/Thread.h"
#include "DataSource.h"
class ReceiveMsgThread :public Thread
{
private:
DataSource* m_pDataSource;
public:
ReceiveMsgThread(void);
ReceiveMsgThread(DataSource* pDataSource);
~ReceiveMsgThread(void);
protected:
void* run();
};
ReceiveMsgThread::ReceiveMsgThread(DataSource* pDataSource)
: m_pDataSource(pDataSource){
}
void* ReceiveMsgThread::run()
{
cout<<"ReceiveMsgThread...................."<<endl;
int data;
while(1)
{
m_pDataSource->ConsumeData(data);
}
return NULL;
}
在main函数中做如下定义:
int _tmain(int argc, _TCHAR* argv[])
{
DataSource* pDataSource = new DataSource();
ReceiveMsgThread* pRecvThread = new ReceiveMsgThread(pDataSource);
SendMsgThread* pSendThread = new SendMsgThread(pDataSource);
pRecvThread->start();
::Sleep(5 * 1000);
pSendThread->start();
getchar();
return 0;
}
运行结果如下:
每次信号量的获取前面必有一次信号量的释放!