最近一段时期准备温习多线程同步相关内容,主要包括关键代码段和各种内核同步对象。先学习最简单的同步方法--Critical Section。所谓关键代码段,是指给一段代码加上锁,要执行这段代码,必须拿到一把钥匙,而且这把钥匙世界上仅存一把,独一无二。
如下代码所示:
CRITICAL_SECTION g_cs;
EnterCriticalSection(&g_cs);
//add your critical code here
....
LeaveCriticalSection(&g_cs);
在执行...这段代码前,必须确保g_cs没有被其他线程占有,否则线程就在此处挂起。通过这种方式可以保护某个资源,不被多个线程同时访问。
以下代码演示了两个线程在使用Critical Section和不使用的条件下的输出结果:
// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头中排除极少使用的资料
#include <stdio.h>
#include <tchar.h>
#include <iostream>
// critical_section.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
using namespace std;
CRITICAL_SECTION g_cs;
int g_var = 0;
DWORD WINAPI ThreadProc(LPVOID
lpParam)
{
cout
<< "child thread started!\n";
for(int
i=0;i<30;i++)
{
//EnterCriticalSection(&g_cs);
cout
<< "The " << "child ";
cout
<< "thread " << "enter ";
cout
<< "the CS!" << "\n";
g_var++;
cout
<< "g_var added by 1: g_var = " << g_var << endl;
cout
<< "The " << "child " << "thread
" << "leave " << "the CS!" <<
"\n";
//LeaveCriticalSection(&g_cs);
}
cout
<< "child thread ended!\n";
return
0;
}
int _tmain(int argc, _TCHAR*
argv[])
{
cout
<< "main thread started!\n";
InitializeCriticalSection(&g_cs);
DWORD
tid;
HANDLE
hThread = CreateThread(0, 0, ThreadProc, 0, 0, &tid);
for(int
i=0;i<30;i++)
{
//EnterCriticalSection(&g_cs);
cout
<< "The " << "main " << "thread
";
cout
<< "enter " << "the CS!" <<
"\n";
g_var--;
cout
<< "g_var minused by 1: g_var = " << g_var << endl;
cout
<< "The " << "main " << "thread
";
cout
<< "enter " << "the CS! " <<
"\n";
//LeaveCriticalSection(&g_cs);
}
WaitForSingleObject(hThread,
INFINITE);
CloseHandle(hThread);
DeleteCriticalSection(&g_cs);
cout
<< "main thread ended!\n";
return
0;
}
将如下代码的注释去掉即变成了使用Critical Section的实例。
//EnterCriticalSection(&g_cs);
//LeaveCriticalSection(&g_cs);
EnterCriticalSection()的缺点是如果g_cs仍未被其他线程释放,就一直在此处挂起,如果不想线程挂起,可以用替代函数:
BOOL WINAPI TryEnterCriticalSection(
__inout LPCRITICAL_SECTION lpCriticalSection
);
下一章将讲述互斥--Mutex的使用。