关于c ++:CreateMutex从不返回ERROR_ALREADY_EXISTS

CreateMutex never returns ERROR_ALREADY_EXISTS

我正在使用CreateMutex停止多个应用程序以同时运行某些功能。这些函数在dll中,因此可以由同一应用程序或单独的应用程序调用。该dll与硬件通信,因此如果其他功能已在运行,则我想返回"繁忙",而不必等待。我认为最好的方法是使用CreateMutex而不是OpenMutex的组合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int FunctionExposedByDll()
{

    hMutexAPI = CreateMutex(0, 0, API_RUNNING_MUTEXT );

    if (!hMutexAPI )
    {
        DWORD dwErr = GetLastError();

        if (dwErr == ERROR_ALREADY_EXISTS )
            return MY_ERROR_BUSY;
    }

    // actual function here

    CloseHandle( hMutexAPI );

}

因此,如果已经创建了互斥锁,则应该获取ERROR_ALREADY_EXISTS,它告诉我系统正在执行api,并且应该返回。但是,即使先前的函数未返回且互斥锁句柄未关闭,上述代码也始终返回有效的互斥锁。

我还尝试了CreateMutexEx函数,在这种情况下,当我第二次尝试使用它时,当我期望ERROR_ALREADY_EXISTS时它返回ERROR_ACCESS_DENIED。所以我的问题是,要获得互斥体已经存在的正确状态,我需要怎么做?

我正在使用Windows 7

**更新**

基于Rob K的答案,我将代码更改为以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int FunctionExposedByDll()
{

    hMutexAPI = CreateMutex(0, 0, API_RUNNING_MUTEXT );


    DWORD dwErr = GetLastError();

    if (dwErr == ERROR_ALREADY_EXISTS )
    {
        CloseHandle( hMutexAPI); // i have to call this but it contributes to first chance exception too!
        return MY_ERROR_BUSY;
    }

    // actual function here

    CloseHandle( hMutexAPI );

}

现在,我正在获取/读取信号量的正确状态,但是释放是一个问题。如果我在处于"繁忙状态"时不释放它,那么即使其他API已完成,我也总是会收到ERROR_ALREADY_EXISTS。因此,CloseHandle()修复了该问题,但又产生了另一个问题。当我从繁忙状态返回并关闭CloseHandle()时,第一个API稍后完成并想要关闭句柄时,我得到了第一次机会异常。我看不出该如何避免!!


这不是使用CreateMutex()的正确方法。 CreateMutex()(几乎)总是成功地将有效的句柄返回给互斥锁。从链接的MSDN文档中:"如果互斥锁是命名的互斥锁,并且该函数调用之前存在该对象,则返回值是现有对象的句柄,GetLastError返回ERROR_ALREADY_EXISTS ..."

再次引用:"两个或多个进程可以调用CreateMutex来创建相同的命名互斥锁。第一个进程实际上创建了互斥锁,具有足够访问权限的后续进程只是打开了现有互斥锁的句柄。这使多个进程可以获取相同的互斥量,同时使用户不必承担确保首先启动创建过程的责任。"

您要执行的操作是使用CreateMutex()打开互斥锁的句柄,然后使用超时值为0的WaitForSingleObject()尝试使用它。如果WaitForSingleObject()无法使用互斥锁,则返回MY_ERROR_BUSY。如果确实成功获取了互斥锁,请在使用完该互斥锁后调用ReleaseMutex()

预计到达时间:

如果WaitForSingleObject返回WAIT_OBJECT_0或WAIT_ABANDONED,则您拥有互斥锁(例如,它会发出信号),并且必须在调用CloseHandle之前调用ReleaseMutex放弃所有权(例如,取消对其发出信号)。

如果返回WAIT_TIMEOUT,则您不拥有该互斥锁,而只能调用CloseHandle。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int FunctionExposedByDll()
{

    HANDLE hMutexAPI = CreateMutex(0, 0, API_RUNNING_MUTEXT );

    int rval = MY_ERROR_BUSY;    
    if ( hMutexAPI )
    {
        DWORD wait_success = WaitForSingleObject( hMutexAPI, 0 );
        if ( wait_success == WAIT_OBJECT_0 || wait_success == WAIT_ABANDONED )
        {


            // actual function here

            ReleaseMutex( hMutexAPI );
            rval = SUCCESS_VALUE;
        }
        CloseHandle( hMutexAPI );
    }
    return rval;
}

从此处开始,您应该花一些时间来熟悉基本的进程间通信原语:http://en.wikipedia.org/wiki/Mutex

再次预计
我认为C ++ 11可能已将IPC原语添加到标准库中,看来它们具有:

1
2
http://en.cppreference.com/w/cpp/thread/mutex,
http://en.cppreference.com/w/cpp/thread/lock_guard

如果您使用的是支持C ++ 11的编译器(例如Visual Studio 2013),请使用它们而不是系统原语。

还有一个编辑...
正如评论中指出的那样,C ++标准库原语不可用于进程间通信,而仅可用于同步同一进程中的线程。 (非常令人失望。)

相反,请尽可能使用Boost.Interprocess。


无论如何,CreateMutex返回有效的句柄。也就是说,对!hMutexAPI的测试失败,并且您永远不会输入该子句。