浅谈线程同步 (一)

2014-11-24 03:18:28 · 作者: · 浏览: 0

现代操作系统都支持多线程操作了,多线程操作带来的一个麻烦就是多个线程对共享数据的访问。假设我们有线程A

和线程B,它们需要访问同一内存区域,线程A写,线程B读。一般情况下我们是希望线程A写操作完成后再进行读操

作或者线程B读操作完成后我们再进行写操作。但是在多线程中,可能由于线程A分配的时间片用完了或者其他原因导

致线程A的写操作还没完成就调用线程B来对这块共享内存进行读操作,也有可能在线程B的读操作还没完成就调用线

程A来对这块共享内存进行写操作,这些情况都有可能导致严重的逻辑错误。为了解决这一现象,我们就需要一种机

制使得各个线程能够协同工作,这就是我们所讲的线程同步机制了。


Windows系统中用于线程同步的常用机制有:

互斥对象(Mutex)

事件对象(Event)

信号量(Semaphore)

临界区(critical section)

可等待计时器(Waitable Timer)


在学习线程同步之前,我们需要先来了解下同步过程中最重要的两个概念:同步对象和等待函数。

同步对象主要有(Mutex、Event、Semaphore、critical section)。同步对象一般具有两种状态:标志的和未标志的。线

程根据是否已经完成操作将同步对象设置为标志的或未标志的。

而等待函数的功能是专门用于等待同步对象状态改变。一个线程调用等待函数后执行会暂停,直到同步对象的状态变

为标志的之后,等待函数才会返回,线程才能继续执行下去。

关于上面所讲的几种主要同步对象的概念,这篇临界区,互斥量,信号量,事件的区别讲的很详细,不懂的朋友可以

去肯看。


线程同步的过程:

1、在需要进行线程同步的进程中定义某种同步对象,同步对象必需是全局的,以保证需要同步的所有线程都可以访

问到同步对象。

2、开始时,所有的线程相互独立地运行

3、当某一线程(为了方便描述设为线程A)需要访问共享资源时,若同步对象为“未标志的”,继续等待;反之,线程A将

同步对象设为“未标志的”,并对共享资源进行访问,访问结束后再将同步对象设为“标志的”使得其它线程可以访问

共享资源。


为了便于理解线程同步的过程,我们可以把我们需要访问的共享资源当成是一件放在房间里的东西,而同步对象当成

是门上的锁,而需要访问资源的线程就可以当做是取东西的人了,“标志的”状态表示门是开的,“未标志的”状态表示

门是锁着的,而此时钥匙在进去的那个人手里。当某人进入房间后,就将门锁上,其他人就无法进入了,只有等这个

人出来之后才能进入。


下面是一个我自己写的利用事件对象来同步访问共享内存实例:


[cpp]
#include <windows.h>
#include
#include

TCHAR szSharedBuffer[100] = {0}; //共享内存
HANDLE hEvent; //事件对象句柄

DWORD WINAPI ThreadForWrite (LPVOID lpParam);
DWORD WINAPI ThreadForRead (LPVOID lpParam);

int main()
{
HANDLE hWrite;
HANDLE hRead;

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

hWrite = CreateThread(NULL,
0,
ThreadForWrite,
0,
0,
NULL);
hRead = CreateThread(NULL,
0,
ThreadForRead,
0,
0,
NULL);

SetEvent(hEvent);

while(1);
return 0;
}

DWORD WINAPI ThreadForWrite(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(hEvent, INFINITE);
printf("Please input the shared chars: ");
scanf("%s", szSharedBuffer);
SetEvent(hEvent);
}
return 0;
}

DWORD WINAPI ThreadForRead(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(hEvent, INFINITE);
if (!strlen(szSharedBuffer))
printf("The shared chars is null now!\n");
else
printf("The shared chars is %s\n", szSharedBuffer);
SetEvent(hEvent);
}
return 0;
}

#include
#include
#include

TCHAR szSharedBuffer[100] = {0}; //共享内存
HANDLE hEvent; //事件对象句柄

DWORD WINAPI ThreadForWrite (LPVOID lpParam);
DWORD WINAPI ThreadForRead (LPVOID lpParam);

int main()
{
HANDLE hWrite;
HANDLE hRead;

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

hWrite = CreateThread(NULL,
0,
ThreadForWrite,
0,
0,
NULL);
hRead = CreateThread(NULL,
0,
ThreadForRead,
0,
0,
NULL);

SetEvent(hEvent);

while(1);
return 0;
}

DWORD WINAPI ThreadForWrite(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(hEvent, INFINITE);
printf("Please input the shared chars: ");
scanf("%s", szSharedBuffer);
SetEvent(hEvent);
}
return 0;
}

DWORD WINAPI ThreadForRead(LPVOID lpParam)
{
while (1)
{
WaitForSingleObject(hEvent, INFINITE);
if (!strlen(szSharedBuffer))
printf("The shared chars is null now!\n");
else
printf("The shared chars is %s