gpt4 book ai didi

c++ - boost::asio io_service 和 std::containers 的线程安全

转载 作者:行者123 更新时间:2023-11-28 05:43:05 26 4
gpt4 key购买 nike

我正在使用 boost::asio 构建网络服务,但我不确定线程​​安全性。

io_service.run() 仅从专用于 io_service 工作的线程调用一次

另一方面,

send_message() 可以由后面提到的第二个 io_service 处理程序中的代码调用,也可以在用户交互时由 mainThread 调用。这就是我变得紧张的原因。

std::deque<message> out_queue;

// send_message will be called by two different threads
void send_message(MsgPtr msg){
while (out_queue->size() >= 20){
Sleep(50);
}
io_service_.post([this, msg]() { deliver(msg); });
}

// from my understanding, deliver will only be called by the thread which called io_service.run()
void deliver(const MsgPtr){
bool write_in_progress = !out_queue.empty();
out_queue.push_back(msg);
if (!write_in_progress)
{
write();
}
}

void write()
{
auto self(shared_from_this());

asio::async_write(socket_,
asio::buffer(out_queue.front().header(),
message::header_length), [this, self](asio::error_code ec, std::size_t/)
{

if (!ec)
{
asio::async_write(socket_,
asio::buffer(out_queue.front().data(),
out_queue.front().paddedPayload_size()),
[this, self](asio::error_code ec, std::size_t /*length*/)
{
if (!ec)
{
out_queue.pop_front();
if (!out_queue.empty())
{
write();
}
}

});
}

});

}

这种情况安全吗?

类似的第二种情况:当网络线程收到一条消息时,它将它们发布到另一个 asio::io_service 中,该服务也由它自己的专用线程运行。此 io_service 使用 std::unordered_map 来存储回调函数等。

std::unordered_map<int, eventSink> eventSinkMap_;

//...

// called by the main thread (GUI), writes a callback function object to the map
int IOReactor::registerEventSink(std::function<void(int, std::shared_ptr<message>)> fn, QObject* window, std::string endpointId){
util::ScopedLock lock(&sync_);

eventSink es;
es.id = generateRandomId();
// ....
std::pair<int, eventSink> eventSinkPair(es.id, es);

eventSinkMap_.insert(eventSinkPair);

return es.id;
}

// called by the second thread, the network service thread when a message was received
void IOReactor::onMessageReceived(std::shared_ptr<message> msg, ConPtr con)
{
reactor_io_service_.post([=](){ handleReceive(msg, con); });
}

// should be called only by the one thread running the reactor_io_service.run()
// read and write access to the map
void IOReactor::handleReceive(std::shared_ptr<message> msg, ConPtr con){
util::ScopedLock lock(&sync_);
auto es = eventSinkMap_.find(msg.requestId);
if (es != eventSinkMap_.end())
{
auto fn = es->second.handler;
auto ctx = es->second.context;
QMetaObject::invokeMethod(ctx, "runInMainThread", Qt::QueuedConnection, Q_ARG(std::function<void(int, std::shared_ptr<msg::IMessage>)>, fn), Q_ARG(int, CallBackResult::SUCCESS), Q_ARG(std::shared_ptr<msg::IMessage>, msg));

eventSinkMap_.erase(es);
}

首先:我什至需要在这里使用锁吗?

Ofc 这两种方法都访问 map ,但它们访问的元素不同(receiveHandler 无法尝试访问或读取尚未注册/插入 map 的元素)。那是线程安全的吗?

最佳答案

首先,缺少了很多上下文(onMessageReceived在哪里被调用,ConPtr是什么?你的问题太多了,我给你不过,一些具体的建议会对您有所帮助。

  1. 你应该在这里紧张:

    void send_message(MsgPtr msg){
    while (out_queue->size() >= 20){
    Sleep(50);
    }
    io_service_.post([this, msg]() { deliver(msg); });
    }

    除非 out_queue 是线程安全的,否则检查 out_queue->size() >= 20 需要同步。

    io_service_.post 的调用是安全的,因为io_service 是线程安全的。由于您有一个专用的 IO 线程,这意味着 deliver() 将在该线程上运行。现在,您也需要同步。

    我强烈建议在那里使用适当的线程安全队列。

  2. Q. first of all: Do I even need to use a lock here?

    是的,您需要锁定才能进行 map 查找(否则您会在主线程插入接收器时发生数据竞争)。

    不需要在调用期间需要锁定(事实上,这似乎是一个非常不明智的想法,可能会导致性能问题或锁定)。由于 Iterator invalidation rules,引用仍然有效.

    删除当然需要再次加锁。我会修改代码一次删除和删除,只有在释放锁后才调用接收器。 注意 你必须在这里考虑异常(在你的代码中,当调用期间出现异常时,接收器不会被删除(永远?)。这对你来说可能很重要。

    Live Demo

    void handleReceive(std::shared_ptr<message> msg, ConPtr con){
    util::ScopedLock lock(&sync_);
    auto es = eventSinkMap_.find(msg->requestId);
    if (es != eventSinkMap_.end())
    {
    auto fn = es->second.handler;
    auto ctx = es->second.context;
    eventSinkMap_.erase(es); // invalidates es

    lock.unlock();
    // invoke in whatever way you require
    fn(static_cast<int>(CallBackResult::SUCCESS), std::static_pointer_cast<msg::IMessage>(msg));
    }
    }

关于c++ - boost::asio io_service 和 std::containers 的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36737017/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com