boost :: interprocess_exception - 创建shared_memory_object时的library_error异常

时间:2016-06-27 04:16:43

标签: c++ exception boost interprocess

在极少数情况下(事实上在单个客户端的计算机上),以下代码会引发异常“ library_error ”:

namespace ipc = boost::interprocess;
ipc::shared_memory_object m_shm;
...
bool initAsServer(size_t sharedMemSize)
{
    ipc::permissions perm;
    perm.set_unrestricted();

    try
    {
        m_shm = ipc::shared_memory_object(
            ipc::create_only,
            CNameGenHelper::genUniqueNameUtf8().c_str(), // static std::string genUniqueNameUtf8()
            ipc::read_write, perm);
    }
    catch(const ipc::interprocess_exception& ex)
    {
        logError("failed with exception \"%s\"", ex.what());
        return false;
    }
    ...
}

在日志文件中: [ERR]失败,异常“boost :: interprocess_exception :: library_error”

Boost v1.58,平台win32,vs13。

如果你能帮助我解决这个问题,我将非常感激。提前谢谢!

3 个答案:

答案 0 :(得分:2)

问题原因是事件ID =“6005”的事件,源名称是“系统”Windows日志中的“EventLog”。 Event Viewer - Windows Logs - System. 如果系统日志不包含至少一个这样的事件,则方法 boost :: interprocess :: winapi :: get_last_bootup_time()返回 false boost :: interprocess :: ipcdetail :: windows_bootstamp 构造函数抛出异常。 (使用了定义BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME)。

因此,似乎清除“系统”窗口事件日志就足够了,任何使用Boost共享内存的应用程序都将停止工作。

多么可怕的逻辑:使用Windows事件日志的内容。 似乎这个boost ipc实现错误尚未修复(boost_1_61_0)。

此案例的临时解决方法(无需重启计算机):

bool fixBoostIpcSharedMem6005issue() const
{
    bool result = false;

    HANDLE hEventLog = ::RegisterEventSourceA(NULL, "EventLog");
    if(hEventLog)
    {
        const char* msg = "simple boost shared memory fix for 6005";

        if(::ReportEventA(hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 6005, NULL, 1, 0, &msg, NULL))
            result = true;

        ::DeregisterEventSource(hEventLog);
    }

    return result;
}

使用它并尝试再次使用ipc :: shared_memory_object:)

答案 1 :(得分:1)

该图书馆的一位作者对该问题进行了许多详细的解释:Boost interprocess: Getting boot-up time is unreliable on Windows和此处:Interprocess get_last_bootup_time use of Event Log on Windows is completely unreliable

显然,一个可靠的解决方案是将预处理器常量BOOST_INTERPROCESS_SHARED_DIR_PATH定义为函数调用,该函数调用在引导计算机后始终返回与字符串相同的目录路径。例如,通过格式化文件的更新时间戳,在启动时写入。

答案 2 :(得分:1)

您可以#define BOOST_INTERPROCESS_BOOTSTAMP_IS_SESSION_MANAGER_BASED或BOOST_INTERPROCESS_BOOTSTAMP_IS_LASTBOOTUPTIME来切换到基于注册表或WMI的启动时间检测。 另外,您可以使用BOOST_INTERPROCESS_SHARED_DIR_PATH,但是在Windows上它是无用的,因为它使用了硬编码的路径。 BOOST_INTERPROCESS_SHARED_DIR_FUNC是更好的选择,因为它使您可以定义一个返回共享目录路径的函数。