16.2关键代码段

16.2关键代码段

关键代码段,也成为临界区,工作在用户方式下。它是指一个小代码段,在代码能够执行之前,它必须独占对某些资源的访问权。

16.2.1相关的API函数

在进入关键代码段之前,首先得初始化这样一个关键代码段,这个用InitializeCriticalSection函数实现。

VOID InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection   // address of critical 
                                         // section object
);

//要想进入关键代码段,需要调用EnterCriticalSection函数,以获得指定的临界区对象的所有权;同样的,线程使用完所保护的资源后,需要调用LeaveCriticalSection函数,释放指定临界区对象的所有权;当不再需要临界区对象时候,可以调用DeleteCriticalSection函数释放该对象。

16.2.2利用关键代码段实现线程同步

#include<windows.h>
#include<iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_cs;
void main()
{
    HANDLE hThread1;
    HANDLE hThread2;
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    InitializeCriticalSection(&g_cs);
    Sleep(4000);//让主线程睡四秒,系统给线程1和线程2分配时间片运行
    //关闭事件对象句柄
    DeleteCriticalSection(&g_cs);
}
//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    while(TRUE)
    {
        EnterCriticalSection(&g_cs);
        if(tickets>0)
        {
            Sleep(1);
            cout<<"thread1 sell ticket:"<<tickets--<<endl;
            LeaveCriticalSection(&g_cs);
        }
        else
        {
            LeaveCriticalSection(&g_cs);
            break;
        }
    }
    return 0;
}
//线程2的入口函数
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while(TRUE)
    {
        EnterCriticalSection(&g_cs);
        if(tickets>0)
        {
            Sleep(1);
            cout<<"thread2 sell ticket:"<<tickets--<<endl;
            LeaveCriticalSection(&g_cs);
        }
        else
        {
            LeaveCriticalSection(&g_cs);
            break;
        }
    }
    return 0;
}

//运行结果如图
在这里插入图片描述

16.3线程死锁

//以多线程说,如果线程1拥有临界区对象A,等待临界区对象B的拥有权;而线程2拥有临界区对象B,等待临界区对象A的拥有权,这就造成了死锁。

#include<windows.h>
#include<iostream.h>
DWORD WINAPI Fun1Proc(LPVOID lpParameter);
DWORD WINAPI Fun2Proc(LPVOID lpParameter);
int tickets=100;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
void main()
{
    HANDLE hThread1;
    HANDLE hThread2;
    hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);
    hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);
    CloseHandle(hThread1);
    CloseHandle(hThread2);
    InitializeCriticalSection(&g_csA);
 InitializeCriticalSection(&g_csB);
    Sleep(4000);//让主线程睡四秒,系统给线程1和线程2分配时间片运行
    //关闭事件对象句柄
 DeleteCriticalSection(&g_csA);
    DeleteCriticalSection(&g_csB);
}
//线程1的入口函数
DWORD WINAPI Fun1Proc(LPVOID lpParameter)
{
    while(TRUE)
    {
        EnterCriticalSection(&g_csA);
  Sleep(1);
  EnterCriticalSection(&g_csB);
        if(tickets>0)
        {
            Sleep(1);
            cout<<"thread1 sell ticket:"<<tickets--<<endl;
   LeaveCriticalSection(&g_csB);
            LeaveCriticalSection(&g_csA);
        }
        else
        {
   LeaveCriticalSection(&g_csB);
            LeaveCriticalSection(&g_csA);
            break;
        }
    }
    return 0;
}
//线程2的入口函数
DWORD WINAPI Fun2Proc(LPVOID lpParameter)
{
    while(TRUE)
    {
        EnterCriticalSection(&g_csB);
  Sleep(1);
  EnterCriticalSection(&g_csA);
        if(tickets>0)
        {
            Sleep(1);
            cout<<"thread2 sell ticket:"<<tickets--<<endl;
   LeaveCriticalSection(&g_csA);
            LeaveCriticalSection(&g_csB);
        }
        else
        {
   LeaveCriticalSection(&g_csA);
            LeaveCriticalSection(&g_csB);
            break;
        }
    }
    return 0;
}

//运行结果如图,该售票程序没有卖出一张票。所以实现线程同步时,尽量避免死锁。
在这里插入图片描述

16.4互斥对象、事件对象与关键代码段的比较

互斥对象和事件对象属于内核对象,利用内核对象进行线程同步时,速度比较慢,但是可以在多个进程的各个线程中进行同步。

关键代码段工作在用户方式下,同步速度较快,但在使用相关代码段时候,很容易进入死锁状态。因为在等待进入关键代码段时无法设定超时值。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

身影王座

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值