C++ mutex not locking across windows accounts
当我运行C ++程序时,winAPI互斥锁会正确锁定,因此,如果我尝试运行第二个实例,它将检查是否可以打开锁定的互斥锁:
我得到预期的错误:
到现在为止还挺好
问题是当我有1个程序实例正在运行并切换到其他Windows帐户时。 该互斥锁应该被锁定,但是当我运行第二个实例时,它会忽略该互斥锁已锁定并且仍然会启动!
所以我的问题是这样的:
1 | m_hMutex = ::OpenMutex(SYNCHRONIZE, FALSE, mutexName.c_str()); |
第二次运行时,为什么第二个实例在相同的Windows帐户上运行时,为什么要设置m_hMutex!= NULL ...
但是在第二个实例在新帐户上运行时设置m_hMutex == NULL?
在这两种情况下,函数参数都完全相同,并且此代码在D:\上运行
每个登录的用户都在其自己的桌面会话中运行。为了跨用户会话访问命名的内核对象(如互斥锁),您需要使用
根据
The name can have a"Global" or"Local" prefix to explicitly create the object in the global or session namespace. The remainder of the name can contain any character except the backslash character. For more information, see Kernel Object Namespaces.
并根据内核对象命名空间文档:
The separate client session namespaces enable multiple clients to run the same applications without interfering with each other. For processes started under a client session, the system uses the session namespace by default. However, these processes can use the global namespace by prepending the
"Global\\" prefix to the object name. For example, the following code calls `CreateEvent and creates an event object named CSAPP in the global namespace:
1 CreateEvent( NULL, FALSE, FALSE,"Global\\\\CSAPP" );...
Another use of the global namespace is for applications that use named objects to detect that there is already an instance of the application running in the system across all sessions. This named object must be created or opened in the global namespace instead of the per-session namespace. The more common case of running the application once per session is supported by default because the named object is created in a per session namespace.
另外,您应使用
If
lpName matches the name of an existing named mutex object, this function requests theMUTEX_ALL_ACCESS access right. In this case, thebInitialOwner parameter is ignored because it has already been set by the creating process....
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 returnsERROR_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 withERROR_ACCESS_DENIED and the caller should use theOpenMutex function.
尝试这样的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | mutexName ="Global\\\\MyMutexName"; m_hMutex = ::CreateMutex(NULL, FALSE, mutexName.c_str()); if ((!m_hMutex) && (GetLastError() == ERROR_ACCESS_DENIED)) { m_hMutex = ::OpenMutex(SYNCHRONIZE, FALSE, mutexName.c_str()); } if (!m_hMutex) { ... << mutexName <<" cannot be accessed! Aborting!"; //... } else if (GetLastError() == ERROR_ALREADY_EXISTS) { ... << mutexName <<" is already running on this machine! Aborting!"; //... } else { //... } |
或者,在Vista和更高版本上,可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | mutexName ="Global\\\\MyMutexName"; m_hMutex = ::CreateMutexEx(NULL, mutexName.c_str(), 0, SYNCHRONIZE); if (!m_hMutex) { ... << mutexName <<" cannot be accessed! Aborting!"; //... } else if (GetLastError() == ERROR_ALREADY_EXISTS) { ... << mutexName <<" is already running on this machine! Aborting!"; //... } else { //... } |
问题在于Windows为各种内核对象维护了单独的命名空间。一个名称空间中的对象可以与另一名称空间中的对象具有相同的名称,而不会互相干扰。如果要在所有会话之间共享对象,则必须在全局名称空间中创建对象。
从MSDN
The separate client session namespaces enable multiple clients to run the same applications without interfering with each other. For processes started under a client session, the system uses the session namespace by default. However, these processes can use the global namespace by prepending the"Global\\" prefix to the object name.
进一步阅读:内核对象命名空间