C++:信号/槽库中的线程安全

标签 c++ multithreading thread-safety signals-slots

我正在实现一个信号/插槽框架,并且到了我希望它是线程安全的地步。我已经从 Boost 邮件列表中获得了很多支持,但由于这与 boost 无关,我将在这里提出我的未决问题。

什么时候信号/槽实现(或任何调用自身外部函数的框架,由用户以某种方式指定)被认为是线程安全的?它应该是安全的 w.r.t.它自己的数据,即与其实现细节相关的数据?或者它是否还应该考虑用户的数据,无论传递给框架的函数是什么,这些数据都可能会被修改,也可能不会被修改?

这是邮件列表中给出的示例(编辑:这是一个示例用例——即用户代码——。我的代码在调用 Emitter 之后对象):

int * somePtr = nullptr;
Emitter<Event> em; // just an object that can emit the 'Event' signal    

void mainThread()
{
    em.connect<Event>(someFunction);

    // now, somehow, 2 threads are created which, at some point
    // execute the thread1() and thread2() functions below
}

void someFunction()
{
    // can somePtr change after the check but before the set?
    if (somePtr)
        *somePtr = 17;
}

void cleanupPtr()
{
    // this looks safe, but compilers and CPUs can reorder this code:
    int *tmp = somePtr;
    somePtr = null;
    delete tmp;
}

void thread1()
{
    em.emit<Event>();
}

void thread2()
{
    em.disconnect<Event>(someFunction);
    // now safe to cleanup (?)
    cleanupPtr();
}

在上面的代码中,可能会发生 Event 被发出,导致 someFunction 被执行。如果 somePtr 是非 null,但在 if 之后变为 null,但在赋值之前,我们'有麻烦了。从 thread2 的角度来看,这并不明显,因为它在调用 cleanupPtr 之前断开了 someFunction

我明白为什么这可能会导致麻烦,但这是谁的责任?我的图书馆是否应该保护用户免于以各种不负责任但可以想象的方式使用它?

最佳答案

我怀疑没有明确的好答案,但通过记录您希望对 Emitter 对象的并发访问做出的保证会更加清晰。

一个级别的保证,对我来说是线程安全 promise 所隐含的,是:

  • 对象上的并发操作保证使对象处于一致状态(至少,从访问线程的角度来看是这样。)
  • 非交换操作将按照某种(未知)顺序连续安排的方式执行。

那么问题是,emit 方法在语义上 promise 了什么:将控制权传递给连接的例程,还是对函数求值?如果是前者,那么你的工作听起来已经完成了;如果是后者,那么“按顺序”要求将意味着您需要执行某种程度的同步。

图书馆的用户可以使用任何一种,只要明确 promise 的内容即可。

关于C++:信号/槽库中的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28526119/

相关文章:

c++ - 无法在 std::thread 中传递一维数组

c++ - 这是一个 VC++2010 编译器错误吗?

c++ - 简单记录器实现 C++ 中的详细级别

c++ - 如何在 CLion 中显示 C++ 的参数名称提示?

java - 通知给出 IllegalMonitorStateException

c++ - std::random_shuffle 线程安全吗?

c++ - windows/osx/ipad 上的跨平台 GUI

java - 只能进入第一个线程,不能进入后续线程

c# - List<T>.AddRange() 线程安全吗?

java - 将 "get/check/put"替换为 putIfAbsent