我有多个进程,但当时只能运行一个。这意味着 Process1 正在运行,并且如果 Process2 启动,则 Process2 应该等到 Process1 做完了。我正在为此目的考虑使用 boost named_mutex 。为了避免发生抛出某些异常的互斥锁可能无法释放的情况,看起来 boost :: lock_guard 可能很有用。我想出了以下简化的代码版本。
#include <iostream>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/thread.hpp>
#include <chrono>
#include <thread>
using namespace boost::interprocess;
#pragma warning(disable: 4996)
int main()
{
std::cout << "Before taking lock" << std::endl;
named_mutex mutex(open_or_create, "some_name");
boost::lock_guard<named_mutex> guard(mutex) ;
// Some work that is simulated by sleep
std::cout << "now wait for 10 second" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "Hello World";
}
到目前为止,太好了。当该程序运行时,我按Ctl + C组合键,因此该程序被中止(模拟程序崩溃,未处理的异常等)。之后,当我运行该应用程序时,该程序将挂在下面的代码行上。
named_mutex mutex(open_or_create, "some_name");
boost::lock_guard<named_mutex> guard(mutex) ;
如果我更改了互斥锁名称,则可以正常工作而不会挂起。但是,看起来名为 some_name 的互斥锁以某种不良状态在计算机上以某种方式“被记住”。这会导致任何试图获取名称为 some_name 的互斥锁的应用程序都挂在此代码行上。如果我将此互斥锁名称更改为 some_name2 ,该程序将再次正常运行。
答案 0 :(得分:2)
不幸的是,如this answer至the question linked by @ppetraki above中所述,boost::interprocess:named_mutex
在Windows上使用文件锁,而不是实际的互斥锁。如果您的应用程序异常终止,该文件锁将不会从系统中删除。这实际上是主题to an open issue。
看the source code,我们看到,如果定义了BOOST_INTERPROCESS_USE_WINDOWS
,则internal_mutex_type
映射到windows_named_mutex
,而在内部uses a windows_named_sync
,{{ 3}}最后。我不确定选择这种实现的理由是什么。无论是什么,似乎都没有任何办法让boost::interprocess
在Windows上使用适当的命名互斥量。我建议您使用seems to just be using a file lock自己简单地创建一个命名互斥体,例如:
#include <type_traits>
#include <memory>
#include <stdexcept>
#include <mutex>
#include <iostream>
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
struct CloseHandleDeleter { void operator ()(HANDLE h) const { CloseHandle(h); } };
class NamedMutex
{
std::unique_ptr<std::remove_pointer_t<HANDLE>, CloseHandleDeleter> m;
public:
NamedMutex(const wchar_t* name)
: m(CreateMutexW(nullptr, FALSE, name))
{
if (!m)
throw std::runtime_error("failed to create mutex");
}
void lock()
{
if (WaitForSingleObject(m.get(), INFINITE) == WAIT_FAILED)
throw std::runtime_error("something bad happened");
}
void unlock()
{
ReleaseMutex(m.get());
}
};
int main()
{
try
{
NamedMutex mutex(L"blub");
std::lock_guard lock(mutex);
std::cout << "Hello, World!" << std::endl;
}
catch (...)
{
std::cerr << "something went wrong\n";
return -1;
}
return 0;
}
答案 1 :(得分:1)
有人可以解释造成这种现象的原因吗?
互斥锁是全局的。
如何重设此特定互斥锁的行为?
致电boost::interprocess::named_mutex::remove("mutex_name");
最重要的是,如何在实际应用中避免这种情况?
这取决于您的外部问题。也许更明智的解决方案是使用文件锁。进程销毁后,文件锁将消失。
更新:
我了解互斥锁是全局的,但是导致程序挂起的那个互斥锁会发生什么?
第一个程序获取了互斥锁,但从未释放它,因此仍保持互斥锁。通常会在互斥状态处于不一致状态时保持互斥锁,因此自动释放互斥锁会造成灾难性的后果。
我如何确定互斥体名称是否处于错误状态,以便该调用其上的remove了?
在您的情况下,您确实不能这么做,因为您为该工作选择了错误的工具。用来告诉互斥对象是否处于健全状态的相同逻辑只会解决您的整个问题,因此,互斥对象只会使事情变得更难。而是使用文件锁。将进程名称和进程ID写入文件以帮助进行故障排除可能会很有用。