zoukankan      html  css  js  c++  java
  • 互斥体

    1.等待函数
    1)WaitForSingleObjectDWORD WaitForSingleObject(                
      HANDLE hHandle,        // handle to object                
      DWORD dwMilliseconds   // time-out interval                
    );        
    功能说明:                    
        等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止.                    
    参数:                   
        hHandle    ->内核对象句柄,可以是进程也可以是线程. (窗体不是内核对象,进程和线程是内核对象)                   
        dwMilliseconds    ->等待时间,单位是毫秒  INFINITE(-1)一直等待  (毫秒数过后不管内核对象的状态,等待的线程继续往下走)                  
    返回值:
        WAIT_OBJECT_0(0)            等待对象变为已通知        
        WAIT_TIMEOUT(0x102)            超时    
        (返回是那种原因导致等待的线程继续往下执行)     
    特别说明(内核对象的状态):                    
        1】内核对象中的每种对象都可以说是处于已通知或未通知的状态之中                    
        2】这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的                    
        3】当线程正在运行的时候,线程内核对象处于未通知状态                    
        4】当线程终止运行的时候,它就变为已通知状态                    
        5】在内核中就是个BOOL值,运行时FALSE 结束TRUE(也就是一个结构中的某个成员的值)    
    注意:
        函数的第一个参数为内核对象;
        函数根据传入的内核对象的类型不同处理方式也不同;
        如果内核对象是进程或线程,在目标内核对象变成已通知状态后不会将其改为未通知状态;
        如果是其它内核对象就不一定了;
            例如:连续两次调用该函数;
            ::WaitForSingleObject(hThread1, INFINITE);
            ::WaitForSingleObject(hThread1, INFINITE);
            如果内核对象会在调用该函数后改为未通知状态,程序将卡死;
            原因:
                主线程第一次调用WaitForSingleObject等待线程1执行完;
                线程1执行完,状态变为已通知;
                但WaitForSingleObject将线程1的状态重新变为未通知;
                主线程第二次调用WaitForSingleObject等待线程1变为已通知;
                此时线程1已经执行完,不可能再主动变为已通知状态了;
                主线程一直等待下去;
    实例:
    DWORD WINAPI ThreadProc1(LPVOID lpParameter)                    
    {                    
        for(int i=0;i<5;i++)                
        {                
            printf("+++++++++
    ");            
            Sleep(1000);            
        }                
        return 0;                
    }                    
                        
    int main(int argc, char* argv[])                    
    {                    
        //创建一个新的线程                
        HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1,                 
            NULL, 0, NULL); 
        //主线程将等待线程1进入已通知状态后才能继续运行;线程1运行完后自动进入已通知状态;也就是说输出5次+++++++++后才弹框;      
        DWORD dwCode = ::WaitForSingleObject(hThread1, INFINITE);                
        MessageBox(0,0,0,0);                
        return 0;                
    }                    
    2)WaitForMultipleObjects
    DWORD WaitForMultipleObjects(                        
      DWORD nCount,             // number of handles in array                        
      CONST HANDLE *lpHandles,  // object-handle array                        
      BOOL bWaitAll,            // wait option                        
      DWORD dwMilliseconds      // time-out interval                        
    );
    功能说明:                            
        同时查看若干个内核对象的已通知状态                            
    参数:                            
        nCount    ->要查看内核对象的数量                            
        lpHandles    ->内核对象数组                            
        bWaitAll    ->等到类型  TRUE 等到所有变为已通知  FALSE 只要有一个变为已通知                            
        dwMilliseconds    ->超时时间 ;INFINITE一直等待                            
    返回值:                            
        bWaitAll为TRUE时,返回WAIT_OBJECT_0(0) 代码所以内核对象都变成已通知                            
        bWaitAll为FALSE时,返回最先变成已通知的内核对象在数组中的索引                            
        WAIT_TIMEOUT(0x102)            超时                
    实例:
    DWORD WINAPI ThreadProc1(LPVOID lpParameter)                            
    {                            
        for(int i=0;i<5;i++)                        
        {                        
            printf("+++++++++
    ");                    
            Sleep(1000);                    
        }                        
        return 0;                        
    }                            
                                
    DWORD WINAPI ThreadProc2(LPVOID lpParameter)                            
    {                            
        for(int i=0;i<3;i++)                        
        {                        
            printf("---------
    ");                    
            Sleep(1000);                    
        }                        
                                
        return 0;                        
    }                            
                                
    int main(int argc, char* argv[])                            
    {                            
        HANDLE hArray[2];                        
        //创建一个新的线程                        
        HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1,                         
            NULL, 0, NULL);                    
        //创建一个新的线程                        
        HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2,                         
            NULL, 0, NULL);                    
                                
        hArray[0] = hThread1;                        
        hArray[1] = hThread2;                        
                                
        DWORD dwCode = ::WaitForMultipleObjects(2, hArray,FALSE,INFINITE);     //等到其中一个线程执行完变成已通知状态后弹框;                   
        MessageBox(0,0,0,0);                        
        return 0;                        
    }                            
    2.互斥体
    互斥:
        一个全局变量或资源,可能有多个线程同时访问时会出现线程安全问题;
        可以用互斥机制来解决:一个线程正访问目标资源时其它线程都不能访问;
        临界区就是实现互斥的一种方式;
     
    互斥体也是用来实现互斥的一种方式;
     
    1)创建互斥体
    api函数:
    HANDLE CreateMutex(
      LPSECURITY_ATTRIBUTES lpMutexAttributes,  // SD
      BOOL bInitialOwner,                       // initial owner
      LPCTSTR lpName                            // object name
    );
    lpMutexAttributes    ->三环程序一般传NULL;如果这个参数不为空一般就是内核对象;
    bInitialOwner    ->
    lpName    ->互斥体名称;如果另一个进程想打开该互斥体,需要用到
     
    2)打开互斥体
    HANDLE OpenMutex(
      DWORD dwDesiredAccess,  // access
      BOOL bInheritHandle,    // inheritance option
      LPCTSTR lpName          // object name
    );
    dwDesiredAccess    ->权限;MUTEX_ALL_ACCESS、SYNCHRONIZE
    bInheritHandle    ->返回的句柄是否可继承
    lpName    ->目标互斥体名
     
    3)使用互斥体
    用在进程中通信时;
    和等待函数配合使用;当一个进程访问互斥体时,其它进程无法访问同一名称的互斥体;
    进程一:
    HANDLE g_hMutex = CreateMutex(NULL,FALSE, "XYZ");
     
    进程二:
    HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
    WaitForSingleObject(g_hMutex,INFINITE);
    //逻辑代码
    ReleaseMutex(g_hMutex);
     
    进程三:
    HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");
    WaitForSingleObject(g_hMutex,INFINITE);
    //逻辑代码
    ReleaseMutex(g_hMutex);
    4)互斥体与临界区的区别:
        1】临界区只能用于单个进程间的线程控制.
        2】互斥体可以设定等待超时,但临界区不能.
        3】线程意外终结时,Mutex可以避免无限等待.
        4】Mutex效率没有临界区高.
     
    互斥体是内核对象;
    内核对象是在程序的低2G内存中创建的;
    进程可以共享内核对象,因此互斥体能跨进程通信;
     
    3.实例
    目标:创建一个抢红包程序
    第一步:在第一个文本框中输入一个值,比如1000                    
    第二步:点击抢红包,同时创建3个线程,每个线程循环进行抢红包的操作,每次抢50                    
    第三步:使用Mutex进行线程控制,当第一个文本框中的值<50时,强红包线程结束.                    
                        
    特别说明:                    
    1】四个文本框中的值总和应该为1000                    
    2】强红包线程每次延时50毫秒. (如果不延时,其中一个线程可能瞬间抢完);                   
    3】使用WaitForMultipleObjects监听所有线程,当线程全部结束后 ;                   
       调用CloseHandle关闭句柄. (线程运行完后自动结束,互斥体需要自己来关);   
        等待函数不能直接在WinMain的按钮点击事件中调用,否则主函数将等待导致无法接受消息循环而卡死;
        解决办法是在按钮点击事件中创建一个新的线程,让新线程来创建和控制三个红包线程;                
     
     
    用临界区实现互斥:
    #include<windows.h>
    #include<stdio.h>
    #include "resource.h"
     
    HWND hongbao;
    HWND zg;
    HWND wst;
    HWND smy;
     
    CRITICAL_SECTION cs;
    DWORD num;
     
    //zg
    DWORD WINAPI ThreadProc1(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            EnterCriticalSection(&cs);
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR zgBuffer[10];
            memset(zgBuffer, 0, 10);
            GetWindowText(zg, zgBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD zgNum;
            sscanf(zgBuffer, "%d", &zgNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(zgBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(zgBuffer, "%d", ++zgNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(zg, zgBuffer);
            }
            LeaveCriticalSection(&cs);
            Sleep(10);
        }
     
        return 0;
    }
    //wst
    DWORD WINAPI ThreadProc2(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            EnterCriticalSection(&cs);
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR wstBuffer[10];
            memset(wstBuffer, 0, 10);
            GetWindowText(wst, wstBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD wstNum;
            sscanf(wstBuffer, "%d", &wstNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(wstBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(wstBuffer, "%d", ++wstNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(wst, wstBuffer);
            }
            LeaveCriticalSection(&cs);
            Sleep(10);
            
        }
     
        return 0;
    }
    //smy
    DWORD WINAPI ThreadProc3(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            EnterCriticalSection(&cs);
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR smyBuffer[10];
            memset(smyBuffer, 0, 10);
            GetWindowText(smy, smyBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD smyNum;
            sscanf(smyBuffer, "%d", &smyNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(smyBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(smyBuffer, "%d", ++smyNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(smy, smyBuffer);
            }
            LeaveCriticalSection(&cs);
            Sleep(10);
        }
     
        return 0;
    }
     
    //线程函数
    DWORD WINAPI ThreadProc(                
                 LPVOID lpParameter   // 给线程传递参数       
                 ){
        InitializeCriticalSection(&cs);
     
        //创建线程
        HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);                                   
        HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);                                        
        HANDLE hThread3 = ::CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
        return 0;
    }
     
    //回调函数
    BOOL CALLBACK DialogProc(                                    
                             HWND hwndDlg,  // handle to dialog box            
                             UINT uMsg,     // message            
                             WPARAM wParam, // first message parameter            
                             LPARAM lParam  // second message parameter            
                             )            
    {    
        switch(uMsg)                                
        {    
        case WM_INITDIALOG :
            hongbao = GetDlgItem(hwndDlg, IDC_HB);
            zg = GetDlgItem(hwndDlg, TXT_ZG);
            wst = GetDlgItem(hwndDlg, TXT_WST);
            smy = GetDlgItem(hwndDlg, TXT_SMY);
     
            SetWindowText(zg, TEXT("0"));
            SetWindowText(wst, TEXT("0"));
            SetWindowText(smy, TEXT("0"));
            return TRUE;     
                                        
        case  WM_COMMAND :                                                                   
            switch (LOWORD (wParam))                            
            {
            case IDC_BTN:  
                //获取文本框内容
                TCHAR szBuffer[10];
                memset(szBuffer, 0, 10);
                GetWindowText(hongbao, szBuffer, 10);
                //字符串转数字
                sscanf(szBuffer, "%d", &num);
     
                //清空输入框
                SetWindowText(zg, TEXT("0"));
                SetWindowText(wst, TEXT("0"));
                SetWindowText(smy, TEXT("0"));
     
                HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);        
                //如果不在其他的地方引用它 关闭句柄                
                ::CloseHandle(hThread);            
                return TRUE;  
     
            return FALSE;    
            }                            
            break ;   
        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;        
        }                                    
                                        
        return FALSE ;                                
    }     
     
    //程序入口
    int CALLBACK WinMain(
                         HINSTANCE hInstance,
                         HINSTANCE hPrevHinstance,
                         LPSTR lpCmdLine,
                         int nCmdShow
            ){  
        //创建对话框窗口
        DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc);    
        
        return 0;
    }
    用互斥体实现互斥:
    #include<windows.h>
    #include<stdio.h>
    #include "resource.h"
     
    HWND hongbao;
    HWND zg;
    HWND wst;
    HWND smy;
     
    HANDLE g_hMutex;
    DWORD num;
     
    //zg
    DWORD WINAPI ThreadProc1(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            WaitForSingleObject(g_hMutex,INFINITE);    //等待互斥体
     
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR zgBuffer[10];
            memset(zgBuffer, 0, 10);
            GetWindowText(zg, zgBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD zgNum;
            sscanf(zgBuffer, "%d", &zgNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(zgBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(zgBuffer, "%d", ++zgNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(zg, zgBuffer);
            }
     
            ReleaseMutex(g_hMutex);    //释放互斥体
            Sleep(10);
        }
        return 0;
    }
     
    //wst
    DWORD WINAPI ThreadProc2(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            WaitForSingleObject(g_hMutex,INFINITE);    //等待互斥体
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR wstBuffer[10];
            memset(wstBuffer, 0, 10);
            GetWindowText(wst, wstBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD wstNum;
            sscanf(wstBuffer, "%d", &wstNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(wstBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(wstBuffer, "%d", ++wstNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(wst, wstBuffer);
            }
            ReleaseMutex(g_hMutex);    //释放互斥体
            Sleep(10);
        }
        return 0;
    }
     
    //smy
    DWORD WINAPI ThreadProc3(                
                 LPVOID lpParameter          
                 ){
        while(num > 0){
            WaitForSingleObject(g_hMutex,INFINITE);    //等待互斥体
     
            //获取文本框内容
            TCHAR szBuffer[10];
            memset(szBuffer, 0, 10);
            GetWindowText(hongbao, szBuffer, 10);
     
            TCHAR smyBuffer[10];
            memset(smyBuffer, 0, 10);
            GetWindowText(smy, smyBuffer, 10);
        
            //字符串转数字
            sscanf(szBuffer, "%d", &num);
            DWORD smyNum;
            sscanf(smyBuffer, "%d", &smyNum);
            if(num > 0){
                memset(szBuffer, 0, 10);
                memset(smyBuffer, 0, 10);
                
                sprintf(szBuffer, "%d", --num);
                sprintf(smyBuffer, "%d", ++smyNum);
                SetWindowText(hongbao, szBuffer);
                SetWindowText(smy, smyBuffer);
            }
            ReleaseMutex(g_hMutex);    //释放互斥体
            Sleep(10);
        }
        return 0;
    }
     
     
    //线程函数
    DWORD WINAPI ThreadProc(                
                 LPVOID lpParameter   // 给线程传递参数       
                 ){
        g_hMutex = CreateMutex(NULL,FALSE, "XYZ");    //创建互斥体
        
        HANDLE hArray[3];
        //创建线程
        HANDLE hThread1 = ::CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);                                   
        HANDLE hThread2 = ::CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);                                        
        HANDLE hThread3 = ::CreateThread(NULL, 0, ThreadProc3, NULL, 0, NULL);
        
        //等待所有线程执行完后关闭互斥体
        hArray[0] = hThread1;                        
        hArray[1] = hThread2;
        hArray[2] = hThread3;
        DWORD dwCode = ::WaitForMultipleObjects(3, hArray,FALSE,INFINITE);
        ::CloseHandle(g_hMutex);
     
        return 0;
    }
     
     
    //回调函数
    BOOL CALLBACK DialogProc(                                    
                             HWND hwndDlg,  // handle to dialog box            
                             UINT uMsg,     // message            
                             WPARAM wParam, // first message parameter            
                             LPARAM lParam  // second message parameter            
                             )            
    {    
        switch(uMsg)                                
        {    
        case WM_INITDIALOG :
            hongbao = GetDlgItem(hwndDlg, IDC_HB);
            zg = GetDlgItem(hwndDlg, TXT_ZG);
            wst = GetDlgItem(hwndDlg, TXT_WST);
            smy = GetDlgItem(hwndDlg, TXT_SMY);
     
            SetWindowText(zg, TEXT("0"));
            SetWindowText(wst, TEXT("0"));
            SetWindowText(smy, TEXT("0"));
            return TRUE;     
                                        
        case  WM_COMMAND :                                                                   
            switch (LOWORD (wParam))                            
            {
            case IDC_BTN:  
                //获取文本框内容
                TCHAR szBuffer[10];
                memset(szBuffer, 0, 10);
                GetWindowText(hongbao, szBuffer, 10);
                //字符串转数字
                sscanf(szBuffer, "%d", &num);
     
                //清空输入框
                SetWindowText(zg, TEXT("0"));
                SetWindowText(wst, TEXT("0"));
                SetWindowText(smy, TEXT("0"));
     
                HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);        
                //如果不在其他的地方引用它 关闭句柄                
                ::CloseHandle(hThread);            
                return TRUE;  
     
            return FALSE;    
            }                            
            break ;   
        case WM_CLOSE:
            EndDialog(hwndDlg, 0);
            return TRUE;        
        }                                    
                                        
        return FALSE ;                                
    }     
     
     
    //程序入口
    int CALLBACK WinMain(
                         HINSTANCE hInstance,
                         HINSTANCE hPrevHinstance,
                         LPSTR lpCmdLine,
                         int nCmdShow
            ){  
        //创建对话框窗口
        DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc);    
        
        return 0;
    }
     
            
     
     
  • 相关阅读:
    thymeleaf种处理select,radio和文字回显的问题
    springboot java.util.NoSuchElementException: No value present 异常处理
    Linux报错之ping: www.baidu.com: Name or service not known
    linux虚拟机黑屏解决
    Winscp无法连接linux虚拟机解决
    linux下centos解压时报错: gzip: stdin: not in gzip format   tar: Child returned status 1   tar: Error is not recoverable: exiting now
    CentOS无法使用ifconfig和root密码修改
    python基础学习(linux命令)
    DBCP|C3P0参数详解
    BeanUtilsDBUtils
  • 原文地址:https://www.cnblogs.com/ShiningArmor/p/12132675.html
Copyright © 2011-2022 走看看