CreateMutex永远不会返回ERROR_ALREADY_EXISTS

时间:2014-05-08 16:52:01

标签: c++ multithreading winapi

我正在使用CreateMutex来阻止多个应用程序同时运行某些功能。这些函数在dll中,因此可以由相同的应用程序或单独的应用程序调用。这个dll与硬件对话,所以如果另一个函数已经运行而不是等待它,我想返回'busy'。我认为最好的方法是使用CreateMutex而不是OpenMutex的组合。

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的回答,我已将代码更改为以下内容:

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稍后完成并想要关闭句柄时,我得到第一次机会异常。我不知道怎么能避免这种情况!?

2 个答案:

答案 0 :(得分:3)

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

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

您要做的是使用CreateMutex()打开互斥锁的句柄,然后使用超时值为0的WaitForSingleObject()来尝试接受它。如果WaitForSingleObject()未能使用互斥锁,则返回MY_ERROR_BUSY。如果它成功获取互斥锁,请在完成使用它后解锁ReleaseMutex()

<强> ETA:

如果WaitForSingleObject返回WAIT_OBJECT_0或WAIT_ABANDONED,那么您拥有互斥锁(例如它会发出信号),您必须在调用CloseHandle之前调用ReleaseMutex以放弃所有权(例如,无信号)。

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

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

再次使用ETA 我认为C ++ 11可能已经将IPC原语添加到标准库中,看起来它们有:

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

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

答案 1 :(得分:2)

无论如何,

CreateMutex会返回一个有效的句柄。也就是说,!hMutexAPI的测试失败,您永远不会输入该条款。