• 多线程死锁的产生和解决


    什么是死锁

    线程死锁一般是发生在多个线程的多个锁之间,比如线程A拥有临界区对象LockA的所有权,等待临界区对象LockB;线程B拥有临界区对象LockB的所有权,等待临界区对象LockA;由于两个线程间相互等待各自的锁,并且不释放,就会导致程序一直等待下去,发生死锁;

    死锁伪代码

    //线程A
    EnterCriticalSection(&g_csLockA);
    Sleep(10);
    EnterCriticalSection(&g_csLockB);//等B
    ....
    //对于释放顺序没有影响
    LeaveCriticalSection(&g_csLockA);
    LeaveCriticalSection(&g_csLockB);
    //线程B
    EnterCriticalSection(&g_csLockB);
    Sleep(10);
    EnterCriticalSection(&g_csLockA);//等A
    ....
    //对于释放顺序没有影响
    LeaveCriticalSection(&g_csLockA);
    LeaveCriticalSection(&g_csLockB);

    过分分析

    比如线程A先获得时间片,线程A执行并获得LockA的所有权;sleep(10)之后,线程B获得时间片,线程B执行并获得LockB的所有权;
    当线程A再次活动执行权,线程A会等待LockB的的所有权,同理线程B也还会等LockB的所有权;由于两者都不释放,程序会一致等待下去,发生了死锁;

    解决死锁

    在多线程编程中,为了避免发生这样的情况,可以有两种方法进行预防,这样可以避免死锁的发生;

    • 加锁顺序一致
    //线程A:先等锁A,再等锁B
    EnterCriticalSection(&g_csLockA);
    Sleep(10);
    EnterCriticalSection(&g_csLockB);
    ....
    //对于释放顺序没有影响
    LeaveCriticalSection(&g_csLockA);
    LeaveCriticalSection(&g_csLockB);
    
    
    //线程B:也是先等锁A,再等锁B
    EnterCriticalSection(&g_csLockA);
    Sleep(10);
    EnterCriticalSection(&g_csLockB);
    ....
    //对于释放顺序没有影响
    LeaveCriticalSection(&g_csLockA);
    LeaveCriticalSection(&g_csLockB);
    • 避免锁未释放的场景
    //线程:
    EnterCriticalSection(&g_csLockA);
    Sleep(10);
    EnterCriticalSection(&g_csLockB);
    ....
    //对于释放顺序没有影响
    LeaveCriticalSection(&g_csLockA);
    ....
    return true;
    .....
    LeaveCriticalSection(&g_csLockB);

    死锁实例

    // MultiThread.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    //#include <windows.h>
    #include <iostream>
    #include <afxmt.h>
    using namespace std;
    
    int g_nIndex = 0;
    const int nMaxCnt = 20;
    
    CRITICAL_SECTION g_csLockA;
    CRITICAL_SECTION g_csLockB;
    
    DWORD WINAPI Thread1SynByCS(LPVOID lpParameter)
    {
        while (TRUE)
        {
            //先等锁A,再等锁B,发生死锁,程序一直等待,直至主线程结束
            EnterCriticalSection(&g_csLockA);
            Sleep(10);
            EnterCriticalSection(&g_csLockB);
            //关键代码段-begin
            if (g_nIndex++ < nMaxCnt)
            {
                cout << "Index = "<< g_nIndex << " ";
                cout << "Thread2 is runing" << endl;
                //权限释放
                LeaveCriticalSection(&g_csLockA);
                LeaveCriticalSection(&g_csLockB);
            }
            else
            {
                //权限释放
                LeaveCriticalSection(&g_csLockA);
                LeaveCriticalSection(&g_csLockB);
                //关键代码段-end
                break;
            }
    
        }
    
        return 0;
    }
    
    DWORD WINAPI Thread2SynByCS(LPVOID lpParameter)
    {
        while (TRUE)
        {
            //先等锁B,再等锁A,发生死锁,程序一直等待,直至主线程结束
            EnterCriticalSection(&g_csLockB);
            Sleep(10);
            EnterCriticalSection(&g_csLockA);
            //关键代码段-begin
            if (g_nIndex++ < nMaxCnt)
            {
                cout << "Index = "<< g_nIndex << " ";
                cout << "Thread2 is runing" << endl;
                //权限释放
                LeaveCriticalSection(&g_csLockA);
                LeaveCriticalSection(&g_csLockB);
            }
            else
            {
                //权限释放
                LeaveCriticalSection(&g_csLockA);
                LeaveCriticalSection(&g_csLockB);
                //关键代码段-end
                break;
            }     
        }
    
        return 0;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        HANDLE hThread1 = NULL;
        HANDLE hThread2 = NULL;
    
        //初始化关键代码段对象
        InitializeCriticalSection(&g_csLockA);
        InitializeCriticalSection(&g_csLockB);
    
        //创建新的线程
        hThread1 = CreateThread(NULL,0,Thread1SynByCS,NULL,0,NULL);//立即执行
        hThread2 = CreateThread(NULL,0,Thread2SynByCS,NULL,0,NULL);//立即执行
    
        //无须对新线程设置优先级等操作,关闭之
        //良好的编码习惯
        CloseHandle(hThread1);
        CloseHandle(hThread2);
    
        Sleep(3000);
        //删掉关键代码段对象,并删除系统资源
        DeleteCriticalSection(&g_csLockA);
        DeleteCriticalSection(&g_csLockB);
        return 0;
    }
    
    
  • 相关阅读:
    Pycharm
    Python
    navicat连接MySQL8.0出现2059错误
    MySQL Community Server 8.0.11下载与安装配置
    pip升级以及导入模块
    pycharm安装
    python环境安装
    js 超级玛丽(未完成)
    js 点名
    js 获取鼠标位置坐标
  • 原文地址:https://www.cnblogs.com/jinxiang1224/p/8468288.html
Copyright © 2020-2023  润新知