用C++封装Win32信号量,同步线程

17 篇文章 0 订阅
12 篇文章 1 订阅

     在Win32环境下编写多线程应用程序,也会常用到信号量Semaphore来进行线程同步。与其相关的一组API包括:CreateSemaphore,ReleaseSemaphore,WaitForSingleObject,和CloseHandle。关于这些API的功能以及参数意义等这里就不多说了。下边,我封装了一个信号量类,以及测试代码。已由本人在VS2005环境下编译,测试通过。

MySemaphore.h

#ifndef Semaphore_Header
#define Semaphore_Header

#include <iostream>
#include <Windows.h>
#include <assert.h>

using namespace std;

//------------------------------------------------------------------------

class CSemaphoreImpl
{
protected:
	CSemaphoreImpl(int n, int max);		
	~CSemaphoreImpl();
	void SetImpl();
	void WaitImpl();
	bool WaitImpl(long lMilliseconds);

private:
	HANDLE m_hSema;
};

inline void CSemaphoreImpl::SetImpl()
{
	if (!ReleaseSemaphore(m_hSema, 1, NULL))
	{
		cout<<"cannot signal semaphore"<<endl;
	}
}

//------------------------------------------------------------------------

/*

 信号量同步机制
 信号量提供一个计数值,可以进行原子操作。V 将计数值加1,使得
 等待该信号量的线程可以被调用(调用Set()),P 将计数值减1,使
 当前线程被挂起,进行睡眠(调用Wait())。
 当信号量的计数值被初始化为0时,调用P操作,将挂起当前线程。
 当信号量被激活,即调用V操作后,被挂起的线程就有机会被重新调度了。

*/

class CMySemaphore: private CSemaphoreImpl
{
public:

	/*
	 创建一个信号量,信号量计数值当前值为参数n,最大值为max。
	 如果只有n,则n必须大于0;如果同时有n和max,则n必须不小
	 于0,且不大于max
	*/
	CMySemaphore(int n);
	CMySemaphore(int n, int max);
	
	/*
	 销毁一个信号量
	*/
	~CMySemaphore();

	/*
	 对信号量计数值做加1动作,信号量变为有信号状态,使得
	 另一个等待该信号量的线程可以被调度
	*/
	void Set();

	/*
	 对信号量计数值做减1动作,信号量变为无信号状态。若
	 计数值变得大于0时,信号量才会变为有信号状态。
	*/
	void Wait();

	/*
	 在给定的时间间隔里等待信号量变为有信号状态,若成功,
	 则将计数值减1,否则将发生超时。
	*/
	void Wait(long lMilliseconds);

	/*
	 在给定的时间间隔里等待信号量变为有信号状态,若成功,
	 则将计数值减1,返回true;否则返回false。
	*/
	bool TryWait(long lMilliseconds);

private:
	CMySemaphore();
	CMySemaphore(const CMySemaphore&);
	CMySemaphore& operator = (const CMySemaphore&);
};

inline void CMySemaphore::Set()
{
	SetImpl();
}


inline void CMySemaphore::Wait()
{
	WaitImpl();
}


inline void CMySemaphore::Wait(long lMilliseconds)
{
	if (!WaitImpl(lMilliseconds))
		cout<<"time out"<<endl;
}

inline bool CMySemaphore::TryWait(long lMilliseconds)
{
	return WaitImpl(lMilliseconds);
}

#endif


MySemaphore.cpp

#include "MySemaphore.h"

CSemaphoreImpl::CSemaphoreImpl(int n, int max)
{
	assert (n >= 0 && max > 0 && n <= max);

	m_hSema = CreateSemaphore(NULL, n, max, NULL);
	if (!m_hSema)
	{
		cout<<"cannot create semaphore"<<endl;
	}
}

CSemaphoreImpl::~CSemaphoreImpl()
{
	CloseHandle(m_hSema);
}

void CSemaphoreImpl::WaitImpl()
{
	switch (WaitForSingleObject(m_hSema, INFINITE))
	{
	case WAIT_OBJECT_0:
		return;
	default:
		cout<<"wait for semaphore failed"<<endl;
	}
}

bool CSemaphoreImpl::WaitImpl(long lMilliseconds)
{
	switch (WaitForSingleObject(m_hSema, lMilliseconds + 1))
	{
	case WAIT_TIMEOUT:
		return false;
	case WAIT_OBJECT_0:
		return true;
	default:
		cout<<"wait for semaphore failed"<<endl;		
	}
	return false;
}

CMySemaphore::CMySemaphore(int n): CSemaphoreImpl(n, n)
{
}

CMySemaphore::CMySemaphore(int n, int max): CSemaphoreImpl(n, max)
{
}


CMySemaphore::~CMySemaphore()
{
}


    下边是测试代码

// MySem.cpp : 定义控制台应用程序的入口点。
//

#include "MySemaphore.h"
#include <process.h>

//创建一个信号量,其计数值当前值为0,最大值为3
CMySemaphore g_MySem(0, 3);

//线程函数
unsigned int __stdcall StartThread(void *pParam)
{
	//休眠100毫秒,确保主线程函数main中
	//创建工作线程下一句g_MySem.Set();先执行
	Sleep(100);

	g_MySem.Wait(); //信号量计数值减1

	cout<<"Do print StartThread"<<endl;

	return (unsigned int)0;
}

int main(int argc, char* argv[])
{
	HANDLE hThread;
	unsigned int uiThreadId;

	assert ( !g_MySem.TryWait(10) );

	g_MySem.Set(); //信号量计数值加1

	g_MySem.Wait(); //信号量计数值减1

	try
	{
		g_MySem.Wait(100);
		cout<<"must timeout"<<endl; //此处发生超时
	}
	catch (...)
	{
		cout<<"wrong exception"<<endl;
	}

	g_MySem.Set();
	g_MySem.Set();
	assert ( g_MySem.TryWait(0) );
	g_MySem.Wait();
	assert ( !g_MySem.TryWait(10) );

	//创建工作线程
	hThread = (HANDLE)_beginthreadex(NULL, 0, &StartThread, NULL, 0, &uiThreadId);

	g_MySem.Set();

	//等待线程结束
	DWORD dwRet = WaitForSingleObject(hThread,INFINITE);
	if ( dwRet == WAIT_TIMEOUT )
	{
		TerminateThread(hThread,0);
	}

	assert ( !g_MySem.TryWait(10) ); //若将断言中的 ! 去掉,则会发生断言错误

	//关闭线程句柄,释放资源
	CloseHandle(hThread);

	system("pause");
	return 0;
}


    编译,运行

 

    可见,在不同的线程,这里是主线程函数main和工作线程函数StartThread都可以对信号量对象g_MySem做 P操作。

 

    欢迎转载,麻烦带上连接http://blog.csdn.net/chexlong/article/details/7089287 谢谢合作!

 

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。 目 录 第1部分C++线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4 1.1.2MutexLock 与MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4 1.1.3一个线程安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4 1.2对象的创建很简单. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5 1.3销毁太难. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7 1.3.1mutex 不是办法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7 1.3.2作为数据成员的mutex 不能保护析构.. . . . . . . . . . . . . . 8 1.4线程安全的Observer 有多难.. . . . . . . . . . . . . . . . . . . . . . . . 8 1.5原始指针有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11 1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13 1.7插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . .. . . . . . 14 1.8应用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21 1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23 1.11.2弱回调. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24 1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26 1.13心得与小结. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26 1.14Observer 之谬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 第2章线程同步精要 2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.1.1只使用非递归的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33 2.1.2死锁. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35 2.2条件变量(condition variable). . . . . . . . . .

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来灵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值