上一篇说明了多线程是存在着问题的,起始就是多线程操作同一数据而不同步的问题。那么如果实现线程的同步呢?
线程的同步有多种实现方式:
互斥内核对象、事件内核对象、可等待的计数器内核对象、信号量内核对象和等待函数等等来实现线程的同步。
我们先用互斥内核对象实现线程同步。
互斥内核对象,能够确保线程拥有对单个资源的互斥访问权,互斥对象包含一个使用数量,一个线程ID和一个计数器。其中ID用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程拥有互斥对象的次数。
使用CreateMutext函数,创建或打开一个互斥对象,然后利用互斥对象完成线程间的同步。
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTESl pMutexAttributes, // 指向安全属性的指针
BOOL bInitialOwner, // 初始化互斥对象的所有者
LPCTSTR lpName // 指向互斥对象名的指针
);
参数 类型及说明
可以使用NULL,表示使用默认的安全性。
bInitialOwner:
表示互斥对象的初始拥有者。如果为真,创建这个互斥对象的线程获得该对象的所有权,否则,该线程不获得该互斥对象的所有权。
lpName :
指定互斥体对象的名字。如果为NULL,则创建一个匿名的互斥对象。
当结束后,使用ReleaseMutex函数进行释放指定对象的所有权。
BOOL WIANPI ReleaseMutex(
HANDLE hMutex
);
DWORD WaitForSingleObject(
HANDLE hHandle,
DWORD dwMilliseconds
);
hHandle为句柄,此处为 hMutex的句柄,
dwMilliseconds为指定时间间隔,单位为毫秒。如果指定一个非零值,函数处于等待状态直到hHandle标记的对象被触发,或者时间到了。如果dwMilliseconds为0,对象没有被触发信号,函数不会进入一个等待状态,它总是立即返回。如果dwMilliseconds为INFINITE,对象被触发信号后,函数才会返回。
WaitForSingleObject函数用来检测hHandle事件的信号状态,在某一线程中调用该函数时,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,线程所等待的对象变为有信号状态,则该函数立即返回;如果超时时间已经到达dwMilliseconds毫秒,但hHandle所指向的对象还没有变成有信号状态,函数照样返回。参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
int tickets = 100;
HANDLE hMutex;
int idx = 0;
DWORD WINAPI ThreadProc1(LPVOID lpThreadParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex, INFINITE);
if (tickets>0)
{
Sleep(1);
printf("thread1 ---- %d \n", tickets--);
}
else
{
break;
}
ReleaseMutex(hMutex);
}
return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpThreadParameter)
{
while (TRUE)
{
WaitForSingleObject(hMutex, INFINITE);
if (tickets > 0)
{
Sleep(1);
printf("thread2 ---- %d \n", tickets--);
}
else
{
break;
}
ReleaseMutex(hMutex);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
//创建线程
HANDLE h1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
HANDLE h2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
CloseHandle(h1);
CloseHandle(h2);
//创建互斥对象
hMutex = CreateMutex(NULL, FALSE, NULL);
/* hMutex = CreateMutex(NULL, TRUE, NULL); //如果第二个参数设置为true 那么此时互斥对象为主线程所有
ReleaseMutex(hMutex); //当第二参数的为True的时候
则需要使用该函数 进行释放互斥对象 只有释放后线程1和线程2才能获取 */system("pause");return 0;}