线程同步之信号量

什么是信号量 

    信号量(semaphore)是操作系统用来解决并发中的互斥和同步问题的一种方法。与互斥量不同的地方是,它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。

    信号量的工作原理以一个停车场为例,假设停车场只有三个车位,那么同一时刻最多只能有三辆车进入,还有其他车来时则必须在入口等待。只有当有一辆车离开停车场,才能允许其他车辆进入,如此往复。这个停车系统中,每辆车就好比一个线程,空车位数量就好比一个信号量,空车位数量限制了可以活动的线程。假如里面依然是三个车位,但是现在改变了规则,要求每次只能停两辆车,那么一开始进入两辆车,后面得等到有车离开才能有车进入,但是得保证最多停两辆车。对于Semaphore而言,就如同一个空车位数量,限制了可活动的线程数

信号量的组成

  1. 计数器:该内核对象被使用的次数
  2. 最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位)
  3. 当前资源数量:标识当前可用资源的数量(带符号的32位)。即表示当前开放资源的个数(注意不是剩下资源的个数),只有开放的资源才能被线程所申请。但这些开放的资源不一定被线程占用完。比如,当前开放5个资源,而只有3个线程申请,则还有2个资源可被申请,但如果这时总共是7个线程要使用信号量,显然开放的资源5个是不够的。这时还可以再开放2个,直到达到最大资源数量。

信号量的规则

信号量的规则如下:

(1)如果当前资源计数大于0,那么信号量处于触发状态(有信号状态),表示有可用资源。

(2)如果当前资源计数等于0,那么信号量属于未触发状态(无信号状态),表示没有可用资源。

(3)系统绝对不会让当前资源计数变为负数

(4)当前资源计数绝对不会大于最大资源计数

创建信号量

HANDLE	WINAPI	
CreateSemaphoreW(
	_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,  // Null 安全属性
	_In_ LONG lInitialCount,  //初始化时,共有多少个资源是可以用的。 0:未触发状//态(无信号状态),表示没有可用资源
	_In_ LONG lMaximumCount,  //能够处理的最大的资源数量   3
	_In_opt_ LPCWSTR lpName   //NULL 信号量的名称
);
  1. 第一个参数表示安全属性,这是创建内核对象函数都会有的参数,NULL表示默认安全属性
  2. 第二个参数表示初始时有多少个资源可用,0表示无任何资源(未触发状态)
  3. 第三个参数表示最大资源数
  4. 第四个参数表示信号量的名称,NULL表示无名称的信号量对象

 增加/释放信号量

ReleaseSemaphore(
    _In_ HANDLE hSemaphore,   //信号量的句柄
    _In_ LONG lReleaseCount,   //将lReleaseCount值加到信号量的当前资源计数上面 0-> 1
    _Out_opt_ LPLONG lpPreviousCount  //当前资源计数的原始值
);
  1. 第一个参数表示信号量句柄,也就是调用创建信号量函数时返回的句柄
  2. 第二个参数表示释放的信号量个数,该值必须大于0,但不能大于信号量的最大计数
  3. 第三个参数表示指向要接收信号量的上一个计数的变量的指针。如果不需要上一个计数, 则此参数可以为NULL 。

关闭句柄


CloseHandle(
    _In_ _Post_ptr_invalid_ HANDLE hObject
);

下面是一个简单程序示例:

#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;

int main() {
	HANDLE semaphore;

	semaphore = CreateSemaphore(NULL, 0, 1, NULL);

	CloseHandle(semaphore);
	return 0;
}

上面这个程序创建了一个初始时0个资源,最大资源数为1的信号量。必须等待ReleaseSemaphore增加信号量后才能被使用。这种最大资源为1的信号量相当于一种特殊的互斥信号量。

资源信号量示例 

下面这段程序创建了两个信号资源,其最大资源都为1;一个初始资源为0,另一个初始资源为1。线程中的for循环每执行一次会将另一个要申请的信号资源的可用资源数+1。因此程序的执行结果为两个线程中的for循环交替执行。

#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;

static HANDLE semOne;
static HANDLE semTwo;
static int num;

/*
* 信号资源semOne初始为0,最大1个资源可用
* 信号资源semTwo初始为1,最大1个资源可用
*/

unsigned WINAPI Read(void* arg) {
	int i;
	for (i = 0; i < 5; i++) {
		fputs("Input num:\n", stdout);
		printf("begin read\n");
		WaitForSingleObject(semTwo, INFINITE);
		printf("beginning read\n");
		scanf("%d", &num);
		ReleaseSemaphore(semOne, 1, NULL);
	}
	return 0;
}

unsigned WINAPI Accu(void* arg) {
	int sum = 0, i;
	for (i = 0; i < 5; ++i) {
		printf("begin Accu\n");
		WaitForSingleObject(semOne, INFINITE);
		printf("beginning Accu\n");
		sum += num;
		printf("sum=%d\n", sum);
		ReleaseSemaphore(semTwo, 1, NULL);
	}
	return 0;	
}

int main() {
	HANDLE hThread1, hThread2;
	semOne = CreateSemaphore(NULL, 0, 1, NULL);//初始值没有可用资源
	semTwo = CreateSemaphore(NULL, 1, 1, NULL);//初始值有一个可用资源


	hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);
	hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);
	WaitForSingleObject(hThread1, INFINITE);
	WaitForSingleObject(hThread2, INFINITE);

	CloseHandle(semOne);
	CloseHandle(semTwo);
	system("pause");
	return 0;
}

运行结果 

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java信号是一种线同步的机制,它可以用来控制同时访问某个资源的线程数。Semaphore类是Java提供的信号实现类,它有两个常用的方法:acquire()和release()。acquire()方法会尝试获取一个许可,如果没有许可可用,则会阻塞线程直到有许可可用。release()方法会释放一个许可,如果有阻塞的线程正在等待许可,则会选择一个线程并将其唤醒。 以下是一个使用Semaphore实现线同步的例子: ```java import java.util.concurrent.Semaphore; public class MyThread implements Runnable { private Semaphore semaphore; private int id; public MyThread(Semaphore semaphore, int id) { this.semaphore = semaphore; this.id = id; } @Override public void run() { try { semaphore.acquire(); System.out.println("Thread " + id + " is running"); Thread.sleep(1000); System.out.println("Thread " + id + " is done"); semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Semaphore semaphore = new Semaphore(2); // 最多允许2个线程同时运行 for (int i = 0; i < 5; i++) { new Thread(new MyThread(semaphore, i)).start(); } } } ``` 上述代码中,Semaphore的初始值为2,表示最多允许2个线程同时运行。在run()方法中,线程首先会尝试获取一个许可,如果没有许可可用,则会阻塞线程直到有许可可用。然后线程会执行一些操作,最后释放许可。在main()方法中,创建了5个线程并启动它们。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值