windows 核心编程之8 用户模式下的线程同步

用户模式下的线程同步

有下面2种情况,需要用到线程同步
1 需要让多个线程同时访问一个资源,同时不能破坏资源的完整性
2 一个线程需要通知另外一个线程,任务完成。


1 原子访问方式:

提供下面以下的原子方式访问的函数:
#include <Windows.h>
#include <stdio.h>

int main()
{
	// 原子方式操作
	LONG volatile ivVariable = 10;
	LONGLONG volatile llVariable = 10;

	// return initial value of first parameter
	// you can use it to do subtraction, first parameter negative
	LONG ltestVar = InterlockedExchangeAdd(&ivVariable, 1);
	LONGLONG llTestVariable = InterlockedExchangeAdd64(&llVariable, 2);

	//
	BOOL volatile bTest = FALSE;

	BOOL bOldValue = (BOOL)InterlockedExchange((LONG volatile*)&bTest, TRUE);

	volatile int*p = new int(10);
	LONG* lptest = new LONG(100);

	LONG* plvalue = (LONG*)InterlockedExchangePointer(&p,lptest);

	delete p;
	delete lptest;

	LONG volatile lvolatileCompateValue = 10;

	// function 参数1与参数3是否相等,不相等不执行操作,
	//相等时,把参数2赋值给参数1,返回值参数1以前的值

	LONG lOldValue = InterlockedCompareExchange(&lvolatileCompateValue, 15, 11);

	// 参数1 是一个指针
	LONG volatile* lpvolatile = new LONG(11);
	LONG* lp = new LONG(11);

	
	LONG* lOldCompateValue =(LONG*) InterlockedCompareExchangePointer((volatile PVOID*)&lpvolatile,(PVOID)lp,(PVOID)lpvolatile);

	return 0;
}


下面是原子访问的链表栈
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>


// 原子方式访问单向链表

typedef struct mydata
{
	int i;
	TCHAR ch[10];
	double dou;

}LISTDATA;

typedef struct _Slist_item
{
	SLIST_ENTRY m_entry;
	LISTDATA m_data;
}LISTTIME,*PLISTTIME;
int main()
{
	
	SLIST_HEADER head;
	SLIST_ENTRY slistEntry;
	LISTTIME ltem;
	PLISTTIME pLitem = NULL;

	InitializeSListHead(&head);

	for (int i = 0; i< 10; i++)
	{
		pLitem = new LISTTIME;
		pLitem->m_data.i = i;
		pLitem->m_data.dou = 100;
		_tcscpy_s(pLitem->m_data.ch,10,TEXT("asdf"));

		InterlockedPushEntrySList( &head, &pLitem->m_entry );
	}

	LONG lSize = QueryDepthSList(&head);

	for (int i = 0; i < 10; ++i)
	{
		pLitem = (PLISTTIME)InterlockedPopEntrySList(&head);
		delete pLitem;
	}

	InterlockedFlushSList(&head);

	return 0;
}



2 高速缓存行

Windows SDK 代码最后释放内存有错,buffer指针移动了,下面的代码,已经改好,增加了一些新信息
#include <windows.h>
#include <malloc.h>    
#include <stdio.h>
#include <tchar.h>

typedef BOOL (WINAPI *LPFN_GLPI)(
								 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, 
								 PDWORD);

int _cdecl _tmain ()
{
	BOOL done;
	BOOL rc;
	DWORD returnLength;
	DWORD procCoreCount;
	DWORD byteOffset;
	PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer, FreeBuffer;
	LPFN_GLPI Glpi;

	Glpi = (LPFN_GLPI) GetProcAddress(
		GetModuleHandle(TEXT("kernel32")),
		"GetLogicalProcessorInformation");
	if (NULL == Glpi) 
	{
		_tprintf(
			TEXT("GetLogicalProcessorInformation is not supported.\n"));
		return (1);
	}

	done = FALSE;
	buffer = NULL;
	returnLength = 0;

	while (!done) 
	{
		rc = Glpi(buffer, &returnLength);

		if (FALSE == rc) 
		{
			if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 
			{
				if (buffer) 
					free(buffer);

				FreeBuffer = buffer=(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(
					returnLength);

				if (NULL == buffer) 
				{
					_tprintf(TEXT("Allocation failure\n"));
					return (2);
				}
			} 
			else 
			{
				_tprintf(TEXT("Error %d\n"), GetLastError());
				return (3);
			}
		} 
		else done = TRUE;
	}

	procCoreCount = 0;
	byteOffset = 0;

	while (byteOffset < returnLength) 
	{
		switch (buffer->Relationship) 
		{
			
		case RelationProcessorCore:
			procCoreCount++;
			break;
		case RelationNumaNode:
			printf("节点信息:\n");
			printf("numaNode = %d\n",buffer->NumaNode.NodeNumber);
			break;
		case RelationCache:
			printf("CPU 高速缓冲区\n");
			printf("关联性 %d\n",buffer->Cache.Associativity);
			printf("Cache %d 缓存\n",buffer->Cache.Level);
			printf("Cache %d 缓存行\n",buffer->Cache.LineSize );
			printf("Cache %dKB 大小\n", buffer->Cache.Size / 1024);
			
			switch(buffer->Cache.Type)
			{
			case CacheData:
				printf("CacheData\n");
				break;
			case CacheInstruction:
				printf("CacheInstruction\n");
				break;
			case CacheTrace:
				printf("CacheTrace\n");
				break;
			case CacheUnified:
				printf("CacheUnified\n");
				break;
			}
			break;
		case RelationProcessorPackage:
			printf("RelationProcessorPackage:\n");
			break;
		default:
			break;
		}
		byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
		buffer++;
		printf("=========================================================\n");

	}

	_tprintf(TEXT("Number of active processor cores: %d\n"), 
		procCoreCount);

	free (FreeBuffer);

	return 0;
}





3 高级线程同步

不要使用旋转锁的方式来,线程之间同步


4 关键段

CRITICAL_SECTION     是关键段的结构体,我们不需要了解结构体的细节,帮助文档也没有它的说明.

下面是初始化关键段得函数,参数是结构体地址

InitializeCriticalSection(&cs);

DeleteCriticalSection(&cs); 这个函数是删除,关键段结构体,必须成对使用,否则资源泄露


EnterCriticalSection(&cs);
//需要保护的资源
LeaveCriticalSection(&cs);

也必须要成对使用

可以使用 TryEnterCriticalSection 来替换 EnterCriticalSection  这个函数会尝试请求资源,如果没有资源,返回false,有资源返回true,同时会更新关键段结构体,所以访问了资源后,可以调用 LeaveCriticalSection。 下面的代码说明情况了。

if(TryEnterCriticalSection(&cs))
{
//需要保护的资源


LeaveCriticalSection(&cs);
}
else
{
//没有资源可以访问
//不需要调用 LeaveCriticalSection;
}

下面的代码介绍了怎么使用关键段

#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <process.h>

class MyCriticalSection
{
public:
	MyCriticalSection(){
		InitializeCriticalSection(&m_cs);
	}
	~MyCriticalSection(){
		DeleteCriticalSection(&m_cs);
	}

	void Lock()
	{
		EnterCriticalSection(&m_cs);
	}
	void UnLock()
	{
		LeaveCriticalSection(&m_cs);
	}

	BOOL TryLock()
	{
		return TryEnterCriticalSection(&m_cs);
	}
	void TryUnLock()
	{
		UnLock();
	}
private:
	CRITICAL_SECTION m_cs;
};

int gSum = 0;
MyCriticalSection criticalsection;

unsigned int WINAPI ThreadFuncOne(LPVOID lparam)
{
	criticalsection.Lock();

	for (int i = 0; i < 100; ++i)
	{
		gSum++;
	}
	criticalsection.UnLock();

	return 0;
}

unsigned int WINAPI ThreadFuncTwo(LPVOID lparam)
{
	criticalsection.Lock();

	for (int i = 0; i < 100; ++i)
	{
		gSum++;
		Sleep(10);
	}

	criticalsection.UnLock();

	return 0;
}
unsigned int WINAPI ThreadFuncThree(LPVOID lparam)
{
	while(!criticalsection.TryLock())
	{
		printf("没有资源可以使用\n");
		Sleep(10);
	}
	
	printf("资源可以使用\n");
	for (int i = 0; i < 100; ++i)
	{
		gSum++;
	}

	criticalsection.TryUnLock();

	return 0;
}

int main(int argc, char **argv)
{
	HANDLE hThread1 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncOne, NULL, 0, NULL);

	HANDLE hThread2 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncTwo, NULL, 0, NULL);

	HANDLE hThread3 = (HANDLE)_beginthreadex(NULL, 0, ThreadFuncThree, NULL, 0, NULL);

	HANDLE harray[3] = {hThread1,hThread2,hThread3};

	WaitForMultipleObjects(_countof(harray),harray,TRUE,INFINITE);

	printf("sum = %d\n", gSum);

	system("pause");

	return 0;
}

初始化的时候可以使用
//初始化的时候,使用旋转锁 单CPU上没有作用
WINBASEAPI
BOOL
WINAPI
InitializeCriticalSectionAndSpinCount(
    __out LPCRITICAL_SECTION lpCriticalSection,
    __in  DWORD dwSpinCount
    );

SetCriticalSectionSpinCount 设置旋转锁的次数,单CPU没有效果,这个函数是没有使用上面那个函数,初始化关键段,在后期使用中,可以使用下面这个函数,来改变!




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值