接着上一篇文章我们继续讨论多线程的问题,这一次我们利用互斥对象(mutex)来解决火车站售票同步问题。

1 利用互斥对象实现线程同步

互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量,一个线程ID

和一个计数器。在这一节我们会用到三个函数,

(1)创建互斥对象CreateMutex函数的原型声明

HANDLE
WINAPI
CreateMutexW(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
_In_ BOOL bInitialOwner,
_In_opt_ LPCWSTR lpName
);
lpMutexAttributes
一个指向SECURITY_ATTRIBUTES结构的指针,可以给该参数传递NULL值,让互斥对象使用默认的安全性。
bInitialOwner
BOOL类型,指定互斥对象初始的拥有者。如果该值为真,则创建这个互斥对象的线程获得该对象的所有权;否则,该线程不获得所创建的互斥对象的所有权。
lpName
指定互斥对象的名称。如果此参数为NULL,则创建一个匿名的互斥对象。

(2)释放指定对象的所有权ReleaseMutex函数的原型声明

BOOL
WINAPI
ReleaseMutex(
_In_ HANDLE hMutex
);
hMutex
需要释放的互斥对象的句柄

(3)请求共享对象使用权函数WaitForSingleObject

WINAPI
WaitForSingleObject(
_In_ HANDLE hHandle,
_In_ DWORD dwMilliseconds
);
hHandle
所请求对象的句柄
dwMilliseconds
指定等待的时间间隔,以毫秒为单位
返回值:
WAIT_OBJECT_0:  指定对象的状态被置为信号状态。
WAIT_TIMEOUT:   超时,并且对象的状态为非信号态。
WAIT_ABANDONED: 指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。
WAIT_FAILED:    调用失败。
下面看我们是如何使用互斥对象实现火车站售票系统的同步问题.
#include <windows.h>
#include <iostream>
using namespace std;

DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);

//int index=0;
int tickets = 100;
HANDLE hMutex;

void main(){

    HANDLE hThread1;
    HANDLE hThread2;

    //创建互斥对象
    hMutex = CreateMutex(NULL,true,NULL);
    计数器增加1,互斥对象内部计数器值为2
    //WaitForSingleObject(hMutex, INFINITE);

    //创建线程
    hThread1 = CreateThread(NULL, 0, Fun1Proc, NULL, 0, NULL);
    hThread2 = CreateThread(NULL, 0, Fun2Proc, NULL, 0, NULL);

    //关闭句柄,函数并没有终止新创建的线程,只是表示在主线程中对新创建的线程的引用不感兴趣,因此将它关闭
    CloseHandle(hThread1);
    CloseHandle(hThread2);

    ReleaseMutex(hMutex);
    //main 函数主线程等待4秒
    Sleep(4000);
    system("pause");
    return;
}

//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter){

    while (true)
    {
        //所请求的对象属于处于有信号状态,该函数才会返回,线程才能继续往下执行
        WaitForSingleObject(hMutex, INFINITE);
        if (tickets > 0)
            cout << "thread1 sell ticket" << tickets-- << endl;
        else
            break;
        //释放当前线程对互斥对象的所有权,让该对象处于已通知状态
        ReleaseMutex(hMutex);
    }
    return 0;
}

DWORD WINAPI Fun2Proc(LPVOID lpParameter){

    while (true)
    {
        //所请求的对象属于处于有信号状态,该函数才会返回,线程才能继续往下执行,注意调用WaitForSingleObject()的位置
        WaitForSingleObject(hMutex, INFINITE);
        if (tickets > 0)
            cout << "thread2 sell ticket" << tickets-- << endl;
        else
            break;
        //释放当前线程对互斥对象的所有权,让该对象处于已通知状态,注意调用WaitForSingleObject()的位置
        ReleaseMutex(hMutex);
    }
    return 0;
}



Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐