C++ 经典线程同步互斥量Mutex 示例解析(十二)

在windows系统中,系统本身为我们提供了很多锁。通过这些锁的使用,一方面可以加强我们对锁的认识,另外一方面可以提高代码的性能和健壮性。常用的锁以下四种:

临界区:C++ 关键段(Critical Section)CS深入浅出 之多线程(七)

event :C++ 经典线程同步 事件Event(九)

信号量:信号量是使用的最多的一种锁结果,也是最方便的一种锁。围绕着信号量,人们提出了很多数据互斥访问的方案,pv操作就是其中的一种。如果说互斥锁只能对单个资源进行保护,那么信号量可以对多个资源进行保护。同时信号量在解锁的时候,可以被另外一个thread进行解锁操作。

互斥量:将是这篇文章所接触到的!

ok!本次Demo参考于MSDN:MSDN

1 首先来熟悉我们将要接触到的系列函数

CreateMutex:

HANDLE WINAPI CreateMutex(
  _In_opt_  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  _In_      BOOL bInitialOwner,
  _In_opt_  LPCTSTR lpName
);

函数参数说明:(CreateMutex:)

第一个参数表示安全控制,一般直接传入NULL

第二个参数用来确定互斥量的初始拥有者。如果传入TRUE表示互斥量对象内部会记录创建它的线程的线程ID号并将递归计数设置为1,由于该线程ID非零,所以互斥量处于未触发状态。如果传入FALSE,那么互斥量对象内部的线程ID号将设置为NULL,递归计数设置为0,这意味互斥量不为任何线程占用,处于触发状态。

第三个参数用来设置互斥量的名称,在多个进程中的线程就是通过名称来确保它们访问的是同一个互斥量。

函数访问值:

成功返回一个表示互斥量的句柄,失败返回NULL

备注:通过CreateMutex返回的句柄有MUTEX_ALL_ACCESS访问权,它可以在需要的句柄互斥对象的任何函数中使用,前提是调用者已被授予访问权限。如果一个互斥体是由一个服务或一个线程正在模拟不同的用户创建的,你可以申请一个安全描述符来互斥,当你创建它,或者通过改变其默认的DACL更改为创建进程的默认安全描述符

OpenMutex:

HANDLE OpenMutex(
DWORDdwDesiredAccess, // access
BOOLbInheritHandle, // inheritance option
LPCTSTRlpName // object name
);

参数说明:

第一个参数表示访问权限,对互斥量一般传入MUTEX_ALL_ACCESS。详细解释可以查看MSDN文档。

第二个参数表示互斥量句柄继承性,一般传入TRUE即可。

第三个参数表示名称。某一个进程中的线程创建互斥量后,其它进程中的线程就可以通过这个函数来找到这个互斥量。

函数访问值:成功返回一个表示互斥量的句柄,失败返回NULL


ReleaseMutex:

BOOL WINAPI ReleaseMutex(
  _In_  HANDLE hMutex
);

参数说明:访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了。


给出CSDN的demo,demo中也有比较详细的注释!

#include <windows.h>
#include <stdio.h>

#define THREADCOUNT 4 

HANDLE ghWriteEvent; 
HANDLE ghThreads[THREADCOUNT];

DWORD WINAPI ThreadProc(LPVOID);

void CreateEventsAndThreads(void) 
{
	int i; 
	DWORD dwThreadID; 

	// Create a manual-reset event object. The write thread sets this
	// object to the signaled state when it finishes writing to a 
	// shared buffer. 

	ghWriteEvent = CreateEvent( 
		NULL,               // default security attributes
		TRUE,               // manual-reset event
		FALSE,              // initial state is nonsignaled
		TEXT("WriteEvent")  // object name
		); 

	if (ghWriteEvent == NULL) 
	{ 
		printf("CreateEvent failed (%d)\n", GetLastError());
		return;
	}

	// Create multiple threads to read from the buffer.

	for(i = 0; i < THREADCOUNT; i++) 
	{
		// TODO: More complex scenarios may require use of a parameter
		//   to the thread procedure, such as an event per thread to  
		//   be used for synchronization.
		ghThreads[i] = CreateThread(
			NULL,              // default security
			0,                 // default stack size
			ThreadProc,        // name of the thread function
			NULL,              // no thread parameters
			0,                 // default startup flags
			&dwThreadID); 

		if (ghThreads[i] == NULL) 
		{
			printf("CreateThread failed (%d)\n", GetLastError());
			return;
		}
	}
}

void WriteToBuffer(VOID) 
{
	// TODO: Write to the shared buffer.

	printf("Main thread writing to the shared buffer...\n");

	// Set ghWriteEvent to signaled

	if (! SetEvent(ghWriteEvent) ) 
	{
		printf("SetEvent failed (%d)\n", GetLastError());
		return;
	}
}

void CloseEvents()
{
	// Close all event handles (currently, only one global handle).

	CloseHandle(ghWriteEvent);
}

int main( void )
{
	DWORD dwWaitResult;

	// TODO: Create the shared buffer

	// Create events and THREADCOUNT threads to read from the buffer

	CreateEventsAndThreads();

	// At this point, the reader threads have started and are most
	// likely waiting for the global event to be signaled. However, 
	// it is safe to write to the buffer because the event is a 
	// manual-reset event.

	WriteToBuffer();

	printf("Main thread waiting for threads to exit...\n");

	// The handle for each thread is signaled when the thread is
	// terminated.
	dwWaitResult = WaitForMultipleObjects(
		THREADCOUNT,   // number of handles in array
		ghThreads,     // array of thread handles
		TRUE,          // wait until all are signaled
		INFINITE);

	switch (dwWaitResult) 
	{
		// All thread objects were signaled
	case WAIT_OBJECT_0: 
		printf("All threads ended, cleaning up for application exit...\n");
		break;

		// An error occurred
	default: 
		printf("WaitForMultipleObjects failed (%d)\n", GetLastError());
		return 1;
	} 

	// Close the events to clean up

	CloseEvents();

	system("pause");
	return 0;
}

DWORD WINAPI ThreadProc(LPVOID lpParam) 
{
	// lpParam not used in this example.
	UNREFERENCED_PARAMETER(lpParam);

	DWORD dwWaitResult;

	printf("Thread %d waiting for write event...\n", GetCurrentThreadId());

	dwWaitResult = WaitForSingleObject( 
		ghWriteEvent, // event handle
		INFINITE);    // indefinite wait

	switch (dwWaitResult) 
	{
		// Event object was signaled
	case WAIT_OBJECT_0: 
		//
		// TODO: Read from the shared buffer
		//
		printf("Thread %d reading from buffer\n", 
			GetCurrentThreadId());
		break; 

		// An error occurred
	default: 
		printf("Wait error (%d)\n", GetLastError()); 
		return 0; 
	}

	// Now that we are done reading the buffer, we could use another
	// event to signal that this thread is no longer reading. This
	// example simply uses the thread handle for synchronization (the
	// handle is signaled when the thread terminates.)

	printf("Thread %d exiting\n", GetCurrentThreadId());
	return 1;
}

运行效果如下:


最后总结下互斥量Mutex

1.互斥量是内核对象,它与关键段都有“线程所有权”所以不能用于线程的同步。

2.互斥量能够用于多个进程之间线程互斥问题,并且能完美的解决某进程意外终止所造成的“遗弃”问题。


C++ 经典线程同步互斥量Mutex 示例解析(十二),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。