簡體   English   中英

正確使用 boost::interprocess::named_mutex

[英]Using boost::interprocess::named_mutex correctly

我在使用 named_mutex 時遇到問題,我試圖用它來確定我的應用程序的另一個實例是否正在運行。

我定義了一個全局變量:

named_mutex dssMutex{ open_or_create, "DeepSkyStacker.Mutex.UniqueID.12354687" };

然后在 main() 中我寫道:

    if (!dssMutex.try_lock()) firstInstance = false;

在 main() 的末尾,在我完成了所有捕獲的事情之后:

dssMutex.unlock();

我遇到的問題是,當這是我的程序在系統中的唯一實例時(剛重啟后),try_lock() 返回 false。 我還在調試日志中看到了這一點(這可能只是 try_lock() 的產物):

Exception thrown at 0x00007FFB838C4FD9 in DeepSkyStacker.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x00007FF5FFF7EF00.

那我做錯了什么?

謝謝大衛

三件事:

  • 如果try_lock返回 false,你不應該unlock
  • 你應該是異常安全的,使用scoped_lock幫助器更容易
  • Boost 的進程間鎖定原語不是健壯的互斥體。 這意味着如果您的進程在沒有解鎖的情況下被硬終止,鎖將被卡住。 據我所知,Windows 上的實現包含一個“啟動時間”字段,用於在重新啟動后恢復鎖定,因此您描述的場景應該不是問題。

例外

除非未處理,否則顯示的異常應該不是問題。 如果您使用的是 Visual Studio,則可以將調試器配置為在拋出或未處理的異常時中斷。 對該消息最好的解釋是它是在內部處理的。 最糟糕的解釋是你沒有處理它。 在那種情況下,它會解釋鎖沒有被釋放。

請注意,異常可能是由於try_lock失敗后嘗試unlock引起的?

代碼示例

以下是我將如何使用延遲作用域鎖來實現異常安全:

#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;

int main(int, char** argv) {
    bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};

    bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
    bool const firstInstance = lk.try_lock();

    std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
    std::this_thread::sleep_for(1s);
    std::cout << " Bye\n" << std::flush;
}

Coliru無法處理它,但這是在本地執行的操作:

在此處輸入圖像描述

信號處理

現在,如前所述,這仍然不夠健壯,但是您可以通過至少處理例如 SIGINT 來使其不那么糟糕(當您在終端中按 Ctrl-C 時,POSIX 會發生什么):

#include <boost/asio.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;

int main(int, char** argv) {
    boost::asio::thread_pool ioc(1);
    boost::asio::signal_set ss(ioc, SIGINT, SIGTERM);
    ss.async_wait([](auto ec, int s) {
        if (ec == boost::asio::error::operation_aborted)
            return;
        std::cerr << "signal " << s << " (" << ec.message() << ")" << std::endl;
    });

    bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};

    bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
    bool const firstInstance = lk.try_lock();

    std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
    std::this_thread::sleep_for(1s);

    std::cout << " Bye\n" << std::flush;

    ss.cancel();
    ioc.join();
}

現在可以中斷進程了:

for a in {1..10}; do sleep "0.$RANDOM"; ./one; done& 
for a in {1..10}; do sleep "0.$RANDOM"; ./two; done&
sleep 3; pkill -INT -f ./one;
sleep 5; pkill -INT -f ./two

在此處輸入圖像描述

如果仔細觀察,處理程序現在實際上沒有執行任何操作。 很可能你想確保它干凈地關閉main

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM