Windows线程同步——信号量对象

1. 概述

信号量内核对象用来对资源计数。与其他所有内核对象相同,它们也包含一个使用计数,但它们还包含另外两个32位值:一个最大资源和一个当前资源计数。最大资源计数表示信号量可以控制的最大资源,当前资源技术表示当前可用资源。
信号量的规则如下:
(1)如果当前资源计数大于0,那么信号量处于触发状态
(2)如果当前资源计数等于0,那么信号量属于未触发状态
(3)系统绝对不会让当前资源计数变为负数
(4)当前资源计数绝对不会大于最大资源计数

信号量与互斥量不同的地方是,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。信号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。

PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。
P操作申请资源:
(1)S减1;
(2)若S减1后仍大于等于零,则进程继续执行;
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。

V操作 释放资源:
(1)S加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。

当程序中向信号量请求一个资源的时候,操作系统会检查资源是否可用,并将可用资源的数量递减,整个过程不会被别的线程打断。只有当资源计数递减完成之后,系统才会允许另外一个线程请求对资源的访问。如果等待函数发现信号量的当前资源计数为0(信号量处于未触发状态),那么系统会让调用线程进去等待状态。当另外一个线程将信号量的当前资源计数递增时,系统会记得那个(或些)还在等待的线程,是他们编程可调度状态(并相应地递减当前资源计数)。

2. 函数API

2.1 创建信号量

HANDLE WINAPI CreateSemaphore(
  _In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  _In_     LONG                  lInitialCount,
  _In_     LONG                  lMaximumCount,
  _In_opt_ LPCTSTR               lpName
);

参数说明:

psa:安全控制,一般传入NULL
lInitialCount:设置信号量的初始计数
lMaximumCount:设置信号量的最大计数
lpName:指定信号量对象的名称

2.2 释放信号量

BOOL WINAPI ReleaseSemaphore(
  _In_      HANDLE hSemaphore,
  _In_      LONG   lReleaseCount,
  _Out_opt_ LPLONG lpPreviousCount
);

参数说明:
hSemaphore:信号量句柄
lReleaseCount:把lReleaseCount的值增加到当前资源技术上
plPreviousCount:返回当前资源计数的原始值

2.3 打开信号量

HANDLE WINAPI OpenSemaphore(
  _In_ DWORD   dwDesiredAccess,
  _In_ BOOL    bInheritHandle,
  _In_ LPCTSTR lpName
);

参数说明

dwDesiredAccess:下述常数之一:
SEMAPHORE_ALL_ACCESS:要求对事件对象的完全访问;
SEMAPHORE_MODIFY_STATE:允许使用ReleaseSemaphore函数;
SYNCHRONIZE:允许同步使用信号机对象。
bInheritHandle:如果允许子进程继承句柄,则设为TRUE。
lpName:指定要打开的对象的名字。

3. 示例代码

DWORD WINAPI my_thread1(LPVOID m_pParameter);	//用户线程1
DWORD WINAPI my_thread2(LPVOID m_pParameter);	//用户线程2
UINT count = 0;									//全局的计数函数
HANDLE m_hSem1, m_hSem2;						//定义一个互斥量句柄

int _tmain(int argc, _TCHAR* argv[])
{
	system("color f0");
	int count_size(50);
	m_hSem1 = ::CreateSemaphore(NULL, 0, 1, NULL);		//初始化信号量
	m_hSem2 = ::CreateSemaphore(NULL, 1, 1, NULL);		//初始化信号量
	HANDLE m_h1 = CreateThread(NULL, NULL, my_thread1, &count_size, NULL, NULL);	//用户线程1
	HANDLE m_h2 = CreateThread(NULL, NULL, my_thread2, &count_size, NULL, NULL);	//用户线程2
	::WaitForSingleObject(m_h1, INFINITE);	//等待子线程结束
	::WaitForSingleObject(m_h2, INFINITE);	//等待子线程结束
	::CloseHandle(m_hSem1);			//关闭句柄
	::CloseHandle(m_hSem2);			
	::CloseHandle(m_h1);
	::CloseHandle(m_h2);
	system("pause");
	return 0;
}

//用户线程1
DWORD WINAPI my_thread1(LPVOID m_pParameter)
{
	UINT* my_count = (UINT*)m_pParameter;
	cout << "thread1" << endl;
	for (int i = 0; i < *my_count; ++i)
	{
		::WaitForSingleObject(m_hSem1, INFINITE);	//等待信号量
		count = i;
		cout << count << "\t";
		ReleaseSemaphore(m_hSem2, 1, NULL);			//释放信号量
	}
	return 0;
}

//用户线程2
DWORD WINAPI my_thread2(LPVOID m_pParameter)
{
	UINT* my_count = (UINT*)m_pParameter;
	cout << "thread2" << endl;
	for (int i = 0; i < *my_count; ++i)
	{
		::WaitForSingleObject(m_hSem2, INFINITE);	//等待信号量
		count = i;
		cout << count << "\t";
		ReleaseSemaphore(m_hSem1, 1, NULL);			//释放信号量
	}
	return 0;
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值