n个进程访问一个临界资源,则设置的互斥信号量_多线程同步和互斥有几种实现方法

n个进程访问一个临界资源,则设置的互斥信号量_多线程同步和互斥有几种实现方法一、【临界区】每个进程中访问临界资源的那段代码称为临界区(Critical Section)(临界 资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区, 进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程 必须互斥地对它进行访问。多个进程中涉及到同一个临界资源的临界区称为相关临界区。【进程进入临界区的调度原则】如果有若干进程要求进入空闲的临界区,一…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

一、【临界区】

每个进程中访问临界资源的那段代码称为临界区(Critical Section)(临界 资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区, 进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程 必须互斥地对它进行访问。
多个进程中涉及到同一个临界资源的临界区称为相关临界区。

【进程进入临界区的调度原则】

如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。
任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区, 则其它所有试图进入临界区的进程必须等待。
进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。
如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。

代码实现如下:

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

using namespace std;

CRITICAL_SECTION  g_cs;		// 临界区全局变量
char g_Str[100];

DWORD WINAPI ThreadFunc1(PVOID pParam)
{ 
   
	EnterCriticalSection(&g_cs);	//进入临界区

	for (int i = 0; i < 100; i++)
	{ 
   
		g_Str[i] = 'Y';			//为数组赋值
		Sleep(10);
	}

	LeaveCriticalSection(&g_cs);

	return 0;
}


DWORD WINAPI ThreadFunc2(PVOID pParam)
{ 
   
	EnterCriticalSection(&g_cs);	//进入临界区

	for (int i = 0; i < 100; i++)
	{ 
   
		g_Str[100 - i - 1] = 'I';	//为数组赋值
		Sleep(10);
	}

	LeaveCriticalSection(&g_cs);

	return 0;
}


int main()
{ 
   
	//初始化临界区

	InitializeCriticalSection(&g_cs);

	HANDLE hTH1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);
	HANDLE hTH2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);

	HANDLE TH[2] = { 
    hTH1, hTH2 };

	//等待所有内核对象,TRUE等待所有信号量有效再往下执行,FALSE当有其中一个信号量有效时有向下运行
	WaitForMultipleObjects(2, TH, FALSE, INFINITE);

	//删除临界区
	DeleteCriticalSection(&g_cs);
	printf(g_Str);

	getchar();

	return 0;
}

二、【事件】

事件的主要用途是标志事件的发生,并以此协调线程的执行顺序。

用来通知线程有一些事件已发生,从而启动后继续任务的开始。

事件对象也可以通过通知操作方式来保持线程的同步,并且可以实现不同进程中的线程同步操作。

实现代码如下:

//线程间通信--》事件 Event

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

using namespace std;

HANDLE evRead, evFinish;

DWORD WINAPI ReadThread(PVOID pParam)
{ 
   
	// 当等待仍在挂起状态的时候,句柄被关闭
	WaitForSingleObject(evRead, INFINITE);

	cout << "Reading Event: " << endl;

	return 0;
}

DWORD WINAPI WriteThread(PVOID pParam)
{ 
   
	cout << "Writing Event: " << endl;
	SetEvent(evRead);


	return 0;
}

int main()
{ 
   
	evRead = CreateEvent(NULL, FALSE, FALSE, NULL);
	evFinish = CreateEvent(NULL, FALSE, FALSE, NULL);

	CreateThread(NULL, 0, ReadThread, NULL, 0, NULL);
	Sleep(1000);
	CreateThread(NULL, 0, WriteThread, NULL, 0, NULL);

	WaitForSingleObject(evFinish, INFINITE);	//等待信号量

	cout << "The Program is End,OK\n\n";
	return 0;
}

三、【互斥量】

互斥量又称互斥锁。互斥量是一个可以处于两态之一的变量:解锁和加锁。

如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量
(mutex)。
互斥量仅仅适用于管理共享资源或一小段代码。
由于互斥量在实现时既容易又有效,这使得互斥量在实现用户空间线程包时非常有 用。

为协调共同对一个共享资源的单独访问而设计的。

实现代码如下:

#include<Windows.h>
#include<iostream>
#include<fstream>
#include<atltime.h> //CTIME 时间类头文件
using namespace std;
fstream fstrobj;
DWORD WINAPI ThreadFunc1(PVOID pParam)
{ 

HANDLE *phMutex = (HANDLE*)pParam;
for (int i = 1; i <= 1000000; i++)
{ 

WaitForSingleObject(*phMutex, INFINITE);
fstrobj << "ThreadFunc1:" << i << endl;
ReleaseMutex(*phMutex);
}
return 0;
}
DWORD WINAPI ThreadFunc2(PVOID pParam)
{ 

HANDLE *phMutex = (HANDLE*)pParam;
for (int i = 1; i <= 1000000; i++)
{ 

WaitForSingleObject(*phMutex, INFINITE);
fstrobj << "ThreadFunc2:" << i << endl;
ReleaseMutex(*phMutex);
}
return 0;
}
int main()
{ 

//获取初始当前时间
CTime timebg = CTime::GetCurrentTime();
int nHour = timebg.GetHour();
int nMin = timebg.GetMinute();
int nSec = timebg.GetSecond();
fstrobj.open("MutexDataFile.txt", ios::out);
if (!fstrobj.is_open())
{ 

cout << "文件打开失败!" << endl;
}
HANDLE hMutex = CreateMutex(NULL, FALSE, L"PrintMutexDataInfo IS:");
HANDLE TH1 = CreateThread(NULL, 0, ThreadFunc1, &hMutex, 0, NULL);
HANDLE TH2 = CreateThread(NULL, 0, ThreadFunc2, &hMutex, 0, NULL);
HANDLE hTH[2] = { 
 TH1, TH2 };
WaitForMultipleObjects(2, hTH, TRUE, INFINITE);  // 等待互斥量对象
CloseHandle(hMutex);
fstrobj.close();
//获取结束当前时间
CTime timeed = CTime::GetCurrentTime();
int nHour2 = timeed.GetHour();
int nMin2 = timeed.GetMinute();
int nSec2 = timeed.GetSecond();
//时间差变量
CTimeSpan timeSpan;
timeSpan = timeed - timebg;
// 统计出执行200万次需要多长时间
cout << "共用时:" << timeSpan.GetHours() << "小时" << timeSpan.GetMinutes()
<< "分钟" << timeSpan.GetSeconds() << "秒" << endl;
return 0;
}

四、【信号量(Semaphores)】

(主要是实现同步,可以跨进程) 信号量是一个内核对象,可用来管理大量有限的系统资源
一个使用计数
32位整数,最大资源数量
32位整数,当前资源数量

信号量使用规则:
当前资源数量大于0,则等待信号量的线程获得资源继续运行,当前资源数量 减1
当前资源数量等于0,则等待信号量的线程继续等待,直到有线程释放信号量, 使当前资源数量大于0

创建信号量

HANDLE CreateSemaphore(  PSECURITY_ATTRIBUTES psa, 
LONG lInitialCount, // initial count 
LONG lMaximumCount,  PCTSTR pszName                    
);

为现有的一个已命名信号机对象创建一个新句柄。

HANDLE OpenSemaphore(
DWORD fdwAccess, 
BOOL bInheritHandle, // inheritance option 
PCTSTR pszName // object name ); 

SEMAPHORE_ALL_ACCESS 要求对信号量的完全访问;
SEMAPHORE_MODIFY_STATE 允许使用ReleaseSemaphore函数;
SYNCHRONIZE 允许使用信号量同步。

释放信号量

ReleaseSemaphore(
HANDLE hSem,
LONG lReleaseCount,
PLONG plPreviousCount
);

等待互斥量

DWORD WaitForSingleObject( 
HANDLE hHandle, 
DWORD dwMilliseconds 
);

实现代码如下:

#include <Windows.h>
#include <stdio.h>
DWORD WINAPI ThreadFunc1(LPVOID lParam);
DWORD WINAPI ThreadFunc2(LPVOID lParam);
DWORD WINAPI ThreadFunc3(LPVOID lParam);
DWORD WINAPI ThreadFunc4(LPVOID lParam);
DWORD WINAPI ThreadFunc5(LPVOID lParam);
DWORD WINAPI ThreadFunc6(LPVOID lParam);
DWORD WINAPI ThreadFunc7(LPVOID lParam);
HANDLE hSM1;
HANDLE hSM2;
HANDLE hSM3;
HANDLE hSM4;
HANDLE hSM5;
HANDLE hSM6;
HANDLE hSM7;
HANDLE hTH1;
HANDLE hTH2;
HANDLE hTH3;
HANDLE hTH4;
HANDLE hTH5;
HANDLE hTH6;
HANDLE hTH7;
int main()
{ 

// 创建6个信号量
hSM1 = CreateSemaphore(NULL, 1, 1, "V");
hSM2 = CreateSemaphore(NULL, 0, 1, "i");
hSM3 = CreateSemaphore(NULL, 0, 1, "c");
hSM4 = CreateSemaphore(NULL, 0, 1, "o");
hSM5 = CreateSemaphore(NULL, 0, 1, "N");
hSM6 = CreateSemaphore(NULL, 0, 1, "B");
hSM7 = CreateSemaphore(NULL, 0, 1, " ");
// 创建6个线程
hTH1 = CreateThread(NULL, 0, ThreadFunc1, NULL, 0, NULL);
hTH2 = CreateThread(NULL, 0, ThreadFunc2, NULL, 0, NULL);
hTH3 = CreateThread(NULL, 0, ThreadFunc3, NULL, 0, NULL);
hTH4 = CreateThread(NULL, 0, ThreadFunc4, NULL, 0, NULL);
hTH5 = CreateThread(NULL, 0, ThreadFunc5, NULL, 0, NULL);
hTH6 = CreateThread(NULL, 0, ThreadFunc6, NULL, 0, NULL);
hTH7 = CreateThread(NULL, 0, ThreadFunc7, NULL, 0, NULL);
// 等待6个线程都执行完毕后
WaitForSingleObject(hTH1, INFINITE);
WaitForSingleObject(hTH2, INFINITE);
WaitForSingleObject(hTH3, INFINITE);
WaitForSingleObject(hTH4, INFINITE);
WaitForSingleObject(hTH5, INFINITE);
WaitForSingleObject(hTH6, INFINITE);
WaitForSingleObject(hTH7, INFINITE);
// 关闭句柄 
CloseHandle(hTH1);
CloseHandle(hTH2);
CloseHandle(hTH3);
CloseHandle(hTH4);
CloseHandle(hTH5);
CloseHandle(hTH6);
CloseHandle(hTH7);
// 关闭信号量
CloseHandle(hSM1);
CloseHandle(hSM2);
CloseHandle(hSM3);
CloseHandle(hSM4);
CloseHandle(hSM5);
CloseHandle(hSM6);
CloseHandle(hSM7);
printf("\n\n\n");
return 0;
}
DWORD WINAPI ThreadFunc1(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM1, INFINITE);
printf("V");
ReleaseSemaphore(hSM2, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc2(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM2, INFINITE);
printf("i");
ReleaseSemaphore(hSM3, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc3(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM3, INFINITE);
printf("c");
ReleaseSemaphore(hSM4, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc4(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM4, INFINITE);
printf("o");
ReleaseSemaphore(hSM5, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc5(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM5, INFINITE);
printf("N");
ReleaseSemaphore(hSM6, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc6(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM6, INFINITE);
printf("B");
ReleaseSemaphore(hSM7, 1, NULL);
}
return 0;
}
DWORD WINAPI ThreadFunc7(LPVOID lParam)
{ 

for (int i = 0; i < 10; i++)
{ 

DWORD dwWait = WaitForSingleObject(hSM7, INFINITE);
printf(" ");
ReleaseSemaphore(hSM1, 1, NULL);
}
return 0;
}

小结

临界区:主要通过对多线程串行化来访问公共资源或一段代码,速度快,适合控制数据访问场合;

互斥量:为协议共同对一个共享资源数据的单独访问而设计的;

信号量:为控制一个具有有限数量用户资源而设计;

事件:用来通知线程有一些事件即将发生,从而启动后继任何的开始。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/170946.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 登录注册HTML页面代码「建议收藏」

    登录注册HTML页面代码「建议收藏」一、注册创建register.html文件,录入如下代码<!DOCTYPEhtml><html><head><metacharset=”UTF-8″><title></title><styletype=”text/css”>form{width:100%;

  • chip seq实验原理及步骤_思科真机实验环境搭建

    chip seq实验原理及步骤_思科真机实验环境搭建实验内容通过实验环境学习了解SR-PCE。xrv_7作为PCE,计算PE1到PE2的路径。网络中IP设置,metric值与之前的实验一致。拓扑图配置流程:配置SRGB在IGP(is-is)中使能segmentrouting和NodeID修改IGP和TE的链路metric配置PCE我们这次主要关注配置PCE的过程。前面的配置可以参考:SR-TEPolicy(思科)—-explicitpath实验SR-TEPolicy(思科)—-dynamicpath实验P

  • 用matlab绘制二元函数图像_二元一次函数用matlab怎么画

    用matlab绘制二元函数图像_二元一次函数用matlab怎么画基于MATLAB的数学图像绘制《MATLAB语言》课程论文基于MATLAB的数学图像绘制姓名:周玉琴学号:[1**********]专业:通信工程班级:通信工程(1)班指导老师:汤全武学院:物理电气信息学院完成日期:2019-12-19基于MATLAB的数学图像绘制(周玉琴[**************]级通信工程1班)[摘要]数学是一门工具化的科学语言,我们用数学解决很多问题。然而在学习数学的同…

  • 卡盟网站程序源码,支持无限分站,货源共享「建议收藏」

    卡盟网站程序源码,支持无限分站,货源共享「建议收藏」服务器系统:cenos7.x64位(购买vps都知道ba?安装7.x以上系统)宝塔安装命令:bt.cn(自行获取)(baota我已经安装好了,接下来给大家演示如何操作搭建卡信乐)ssh输入宝塔命令会自动安装好自己查看一下登陆地址和账号密码就可以登陆面板后安装apache2.4+mysql5.5+php5.6phpadmin4.7(应该都会安装把!)登陆宝塔,打开网站的根目录的home文件夹,上传源码然后解压上传好后解压文件修改vhost文件里的域名创建一个数据库yunos数据库

  • QEMU-KVM自己主动创建虚拟机,以指定IP构造

    QEMU-KVM自己主动创建虚拟机,以指定IP构造

  • 冒泡排序深入具体解释

    冒泡排序深入具体解释

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号