互斥量(mutex)与事件(event)的使用

时间:2022-09-14 23:23:55

互斥量(Mutex)

CreateMutex :创建一个互斥量   

    HANDLE   CreateMutex(  
          LPSECURITY_ATTRIBUTES   lpMutexAttributes, //   pointer   to   security   attributes    
          BOOL   bInitialOwner, //   flag   for   initial   ownership    
          LPCTSTR   lpName   //   pointer   to   mutex-object   name      
        );

    Parameters
   
    lpMutexAttributes [in, optional]
   
        A pointer to a SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle cannot be inherited by child processes.
   
        The lpSecurityDescriptor member of the structure specifies a security descriptor for the new mutex. If lpMutexAttributes is NULL, the mutex gets a default security descriptor. The ACLs in the default security descriptor for a mutex come from the primary or impersonation token of the creator. For more information, see Synchronization Object Security and Access Rights.


    bInitialOwner [in]
   
        If this value is TRUE and the caller created the mutex, the calling thread obtains initial ownership of the mutex object. Otherwise, the calling thread does not obtain ownership of the mutex. To determine if the caller created the mutex, see the Return Values section.


    lpName [in, optional]
   
        The name of the mutex object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.
   
        If lpName matches the name of an existing named mutex object, this function requests the MUTEX_ALL_ACCESS access right. In this case, the bInitialOwner parameter is ignored because it has already been set by the creating process. If the lpMutexAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.
   
        If lpName is NULL, the mutex object is created without a name.
   
        If lpName matches the name of an existing event, semaphore, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.
   
        The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces. Fast user switching is implemented using Terminal Services sessions. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.
   
            Windows 2000:  If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.
   
        The object can be created in a private namespace. For more information, see Object Namespaces.
   
    Return Value
   
    If the function succeeds, the return value is a handle to the newly created mutex object.
   
    If the function fails, the return value is NULL. To get extended error information, call GetLastError.
   
    If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.

OpenMutex :为现有的一个已命名互斥量创建一个新句柄

    HANDLE WINAPI OpenMutex(
      __in  DWORD dwDesiredAccess,
      __in  BOOL bInheritHandle,
      __in  LPCTSTR lpName
    );

    Parameters
   
    dwDesiredAccess [in]
   
        The access to the mutex object. Only the SYNCHRONIZE access right is required to use a mutex; to change the mutex's security, specify MUTEX_ALL_ACCESS. The function fails if the security descriptor of the specified object does not permit the requested access for the calling process. For a list of access rights, see Synchronization Objec t Security and Access Rights.


    bInheritHandle [in]
   
        If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.


    lpName [in]
   
        The name of the mutex to be opened. Name comparisons are case sensitive.
   
        This function can open objects in a private namespace. For more information, see Object Namespaces.
   
            Terminal Services:  The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces.
   
            Windows XP Home Edition:  Fast user switching is implemented using Terminal Services sessions. The first user to log on uses session 0, the next user to log on uses session 1, and so on. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.
   
            Windows 2000:  If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.
   
    Return Value
   
    If the function succeeds, the return value is a handle to the mutex object.
   
    If the function fails, the return value is NULL. To get extended error information, call GetLastError.
   
    If a named mutex does not exist, the function fails and GetLastError returns ERROR_FILE_NOT_FOUND.

CloseHandle :关闭句柄

    BOOL WINAPI CloseHandle(
      __in  HANDLE hObject
    );

    Parameters
   
    hObject [in]
   
        A valid handle to an open object.
   
    Return Value
   
    If the function succeeds, the return value is nonzero.
   
    If the function fails, the return value is zero. To get extended error information, call GetLastError.
   
    If the application is running under a debugger, the function will throw an exception if it receives either a handle value that is not valid or a pseudo-handle value. This can happen if you close a handle twice, or if you call CloseHandle on a handle returned by the FindFirstFile function instead of calling the FindClose function.

事件(Event)

CreateEvent :创建一个事件对象.

    HANDLE WINAPI CreateEvent(
      __in_opt  LPSECURITY_ATTRIBUTES lpEventAttributes,
      __in      BOOL bManualReset,
      __in      BOOL bInitialState,
      __in_opt  LPCTSTR lpName
    );

    Parameters
   
    lpEventAttributes [in, optional]
   
        A pointer to a SECURITY_ATTRIBUTES structure. If this parameter is NULL, the handle cannot be inherited by child processes.
   
        The lpSecurityDescriptor member of the structure specifies a security descriptor for the new event. If lpEventAttributes is NULL, the event gets a default security descriptor. The ACLs in the default security descriptor for an event come from the primary or impersonation token of the creator.
    bManualReset [in]
   
        If this parameter is TRUE, the function creates a manual-reset event object, which requires the use of the ResetEvent function to set the event state to nonsignaled. If this parameter is FALSE, the function creates an auto-reset event object, and system automatically resets the event state to nonsignaled after a single waiting thread has been released.
    bInitialState [in]
   
        If this parameter is TRUE, the initial state of the event object is signaled; otherwise, it is nonsignaled.
    lpName [in, optional]
   
        The name of the event object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.
   
        If lpName matches the name of an existing named event object, this function requests the EVENT_ALL_ACCESS access right. In this case, the bManualReset and bInitialState parameters are ignored because they have already been set by the creating process. If the lpEventAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.
   
        If lpName is NULL, the event object is created without a name.
   
        If lpName matches the name of another kind of object in the same name space (such as an existing semaphore, mutex, waitable timer, job, or file-mapping object), the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.
   
        The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces. Fast user switching is implemented using Terminal Services sessions. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.
   
            Windows 2000:   If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.
   
        The object can be created in a private namespace. For more information, see Object Namespaces.
   
    Return Value
   
    If the function succeeds, the return value is a handle to the event object. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.
   
    If the function fails, the return value is NULL. To get extended error information, call GetLastError.

openevent :为现有的一个已命名事件对象创建一个新句柄

    HANDLE WINAPI OpenEvent(
      __in  DWORD dwDesiredAccess,
      __in  BOOL bInheritHandle,
      __in  LPCTSTR lpName
    );

    Parameters
   
    dwDesiredAccess [in]
   
        The access to the event object. The function fails if the security descriptor of the specified object does not permit the requested access for the calling process. For a list of access rights, see Synchronization Object Security and Access Rights.
    bInheritHandle [in]
   
        If this value is TRUE, processes created by this process will inherit the handle. Otherwise, the processes do not inherit this handle.
    lpName [in]
   
        The name of the event to be opened. Name comparisons are case sensitive.
   
        This function can open objects in a private namespace. For more information, see Object Namespaces.
   
            Terminal Services:  The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Namespaces.
   
            Windows XP Home Edition:  Fast user switching is implemented using Terminal Services sessions. The first user to log on uses session 0, the next user to log on uses session 1, and so on. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users.
   
            Windows 2000:  If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.
   
    Return Value
   
    If the function succeeds, the return value is a handle to the event object.
   
    If the function fails, the return value is NULL. To get extended error information, call GetLastError.

事件(event)与互斥量(mutex)区别

事件(event)
    事件是用来同步地位不相等的线程的,事件可以用来使一个线程完成一件事情,然后另外的线程完成剩下的事情。事件的使用很灵活,自动 事件的激发态是由人工来控制的,而Mutex在释放(releaseMetux)后就一直处于激发态,直到线程WaitForSingleObject。 事件可以用来控制经典的读写模型和生产者和消费者模型。相应的方式为,生成者等待消费者的消费,再消费者消费完后通知生产者进行生产。
互斥量(Mutex)
    Mutex 是排他的占有资源,一般用于地位相等的现在进行同步,每个线程都可以排他的访问一个资源或代码段,不存在哪个线程对资源访问存在优先次序。一个线程只能在 Mutex处于激发态的时候访问被保护的资源或代码段,线程可以通过WaitForSingelObject来等待Mutex,在访问资源完成之 后,ReleaseMutex释放Mutex,此时Mutex处于激发态。Mutex具有成功等待的副作用,在等待到Mutex后,Mutex自动变为未 激发态,直到调用ReleaseMutex使Mutex变为激发态为止。自动事件也具有成功等待的副作用。手动事件没有,必须ResetEvent使手动 事件变为未激发态。进程和线程也没有成功等待的副作用。当线程或者进程函数返回时,线程内核对象变为激发态,但WaitForSingleObject并 没有使线程或者进程的内核对象变为未激发态。
总之,事件一般用于控制线程的先后顺序,而Mutex一般用于排他的访问资源。

Mutex示例:

    //A   consule   application 
    CWinApp   theApp; 
    int   iCounter=0; 
    DWORD   threadA(void*   pD) 
    { 
        int   iID=(int)pD; 
        //在内部重新打开 
        HANDLE   hCounterIn=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"sam   sp   44"); 
        for(int   i=0;i<3;i++) 
        { 
            printf("%d   wait   for   object\n",iID); 
            WaitForSingleObject(hCounterIn,INFINITE); 
            int   iCopy=iCounter; 
            Sleep(500*iID); 
            iCounter=iCopy+1; 
            printf("\t\tthread   %d   :   %d\n",iID,iCounter); 
            ReleaseMutex(hCounterIn); 
        } 
        CloseHandle(hCounterIn); 
        return   0; 
    }

    using   namespace   std; 
    int _tmain(int   argc,   TCHAR*   argv[],   TCHAR*   envp[]) 
    { 
        int   nRetCode   =   0; 
        //   initialize   MFC   and   print   and   error   on   failure 
        if   (!AfxWinInit(::GetModuleHandle(NULL),   NULL,   ::GetCommandLine(),   0)) 
        { 
            //   TODO:   change   error   code   to   suit   your   needs 
            cerr   <<   _T("Fatal   Error:   MFC   initialization   failed")   <<   endl; 
            nRetCode   =   1; 
        } 
        else 
        { 
            //   TODO:   code   your   application's   behavior   here. 
            //创建互斥量 
            HANDLE   hCounter=NULL; 
            if(   (hCounter=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"sam   sp   44"))==NULL) 
            { 
            //如果没有其他进程创建这个互斥量,则重新创建 
            hCounter   =   CreateMutex(NULL,FALSE,"sam   sp   44"); 
            } 
            //创建线程 
            HANDLE   hThread[4]; 
            CWinThread*   pT1=AfxBeginThread((AFX_THREADPROC)threadA,(void*)1); 
            CWinThread*   pT2=AfxBeginThread((AFX_THREADPROC)threadA,(void*)2); 
            CWinThread*   pT3=AfxBeginThread((AFX_THREADPROC)threadA,(void*)3); 
            CWinThread*   pT4=AfxBeginThread((AFX_THREADPROC)threadA,(void*)4); 
            hThread[0]=pT1->m_hThread; 
            hThread[1]=pT2->m_hThread; 
            hThread[2]=pT3->m_hThread; 
            hThread[3]=pT4->m_hThread; 
            //等待线程结束 
            WaitForMultipleObjects(4,hThread,TRUE,INFINITE);//5000);// 
            cout<<"over!"<<endl; 
            //关闭句柄 
            CloseHandle(hCounter); 
        } 
        return   nRetCode; 
    }