如何使用 C++ 在不同的线程上调用函数?

Posted

技术标签:

【中文标题】如何使用 C++ 在不同的线程上调用函数?【英文标题】:How can I call a function on a different thread using C++? 【发布时间】:2013-01-08 05:08:35 【问题描述】:

我正在创建一个可供其他团队/产品使用的组件。该组件允许客户端代码发出一组命令,并且在内部这些命令在工作线程上执行 - 使用线程安全队列实现,其中命令被添加到调用者(客户端)线程上的队列中,并在工作线程。

我想以“操作 XYZ 已完成”的形式提供从我的组件到客户端代码的反馈。我可以通过回调轻松地做到这一点,但是回调是在我的工作线程上调用的——我希望它发生在调用者(客户端)线程上。 我该怎么做?

它是一个跨平台组件(Windows、Linux、OS X)。升压可用。我的默认开发编译器是 MS VC++ 2010,即它不是 C++11。

【问题讨论】:

命令排队后客户端线程会发生什么?你阻止它,还是返回给调用者?如果线程被阻塞,则很容易,否则很难。 @MSalters,我们不会阻止 - 我们会尽快返回客户端 【参考方案1】:

安排这种类型的多线程架构的常用方法是让每个线程都有一个阻塞队列。

每个线程在其队列上循环,依次执行每个函子。

要在不同的线程中调用函数,您只需创建一个仿函数并将其添加到该线程队列。

要在 C++ 中创建仿函数,您可以使用 std::functionstd::bind、lamdbas、函数对象或函数指针。见std::function

没有标准的阻塞队列,但是用信号量和互斥体(它们是std::thread库afaik的一部分,也是pthread的一部分)编写一个相当容易。谷歌"blocking queue"

【讨论】:

这看起来很有帮助,但不幸的是特定于 C++11。没有可用的 C++11 解决方案吗?我已更新问题以反映这种需求。 如果boost 可用但C++11 不可用,所有这些都可以使用boost::functionboost::bindboost::thread 完成。 @Chad,你能说得更清楚些吗?也许举个简单的例子? sdt::function/boost::function 只是一个很好的函子和函数指针存储类。没有它们,你没有理由不能做到这一点,只是需要更多的工作。 另外,2010 支持std::functionstd::bind。 Boost 更好,2012 年更好,但它在 2010 年就在那里。用一个简单的程序试试看,看看有什么,没有什么。【参考方案2】:

为什么不重用已设置的命令处理框架,将命令作为答案从工作线程发送回客户端?这需要将您的框架转变为更通用的消息传递框架,但也许它已经适合该目的。

命令对象/结构应包含:

命令的 id(用于回复其完成状态)

可选的颁发者 ID(发送命令的客户端)。

您需要将命令队列从工作线程设置回客户端。每个客户端一个队列是理想的,但是如果您在命令对象/结构中嵌入了一个客户端 ID,您应该能够使用该 ID 来标记答案,以便帮助客户端从全局答案队列中过滤他们的消息。 您还需要在客户端中添加一个函数来在空闲时间检查答案队列,并处理答案以更新 UI 状态。许多 UI 框架(如果不是全部)都支持这种可能性,所以这应该不是问题。如果您的 UI 或框架支持,另一种选择是将队列连接到 UI 事件系统。

请注意,对于 1 个写入器到 1 个读取器的配置,有无锁队列算法,这对于单独的应答队列可能很有趣。

【讨论】:

【参考方案3】:

使用concurrent_queue<std::function<void()>>,然后在主线程上检查这个队列的函数。

【讨论】:

这听起来像是一个有趣的选择,但它不太可能满足我的需求。我没有主线程的所有权,只有工作线程 - 这是因为我正在开发的组件被其他团队/产品使用。他们有主线程,他们可以用它做任何事情,即 Windows 消息循环、永无止境的循环等等等等。

以上是关于如何使用 C++ 在不同的线程上调用函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用从 Swift 代码调用的线程在 C++ 上创建异步调用函数?

如何编写在 C++ openmp 上重用线程的代码?

C++如何运行多个可以随时调用的后台函数线程?

c++线程函数中如何调用该方法下的外部函数?

如何使用 pybind11 在 C++ 线程中调用 Python 函数作为回调

boost::python - 如何从 C++ 在自己的线程中调用 python 函数?