没有SendMessage的C ++中的跨线程操作

时间:2016-12-25 10:00:53

标签: c++ multithreading sendmessage

我正在寻找一种以SendMessage允许的方式执行跨线程操作的方法。换句话说,如何让一个线程在另一个线程中执行某个函数。但我想在没有SendMessage的情况下这样做,因为这需要一个并不总是可用的窗口。

同步或异步都没问题。

.NET使用System.Windows.Threading.Dispatcher类完成它,所以肯定有办法吗?

1 个答案:

答案 0 :(得分:0)

所以我猜我们在这里谈论的是Windows操作系统,对吗?你应该在你的问题中指明。例如,Windows的解决方案可能与Linux的解决方案不同。

现在,关于你的问题,针对这种情况的任何解决方案都会迫使你的线程等待某个事件发生(排队任务),或者无休止地轮询任务。

所以我们谈论的是某种互斥体,条件变量或某种特殊的睡眠功能。

一种(简单)和非便携方式或向其他线程发送“任务”是使用内置Win32 - APC的机制( A 同步 P rocedure C 全部。)

它使用函数QueueUserAPC SleepEx,我在Windows 10 + Visual studio 2015上对此解决方案进行了小测试

namespace details {
    void waitforTask() noexcept {
        SleepEx(INFINITE, TRUE);
    }

    void __stdcall executeTask(ULONG_PTR ptr) {
        if (ptr == 0) {
            return;
        }
        std::unique_ptr<std::function<void()>> scopedPtr(reinterpret_cast<std::function<void()>*>(ptr));
        (*scopedPtr)();
    }
}

template<class F, class ... Args>
void sendTask(void* threadHandle, F&& f, Args&& ... args) {
    auto task =
        std::make_unique<std::function<void()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));

    const auto res = QueueUserAPC(&details::executeTask,
        threadHandle,
        reinterpret_cast<ULONG_PTR>(task.get()));
    if (res == 0) {
        throw std::runtime_error("sendTask failed.");
    }

    task.release();
}

使用示例:

std::thread thread([] {
        for (;;) {
            details::waitforTask();
        }
    });

   sendTask(thread.native_handle(), [](auto literal) {
        std::cout << literal;
   }, "hello world");

此解决方案还演示了如何使用Win32而不会实际污染用C ++代码编写的非相关win32代码编写的业务逻辑。

此解决方案也可以适用于跨平台解决方案,而不是使用内部的,半文档化的win32任务队列,可以使用std::queuestd::function<void()>构建自己的任务队列。而不是睡在警报状态,而是可以使用std::condition_variable。这就是任何线程池在幕后为了获取和执行任务而做的事情。如果您确实需要跨平台解决方案,我建议使用Google搜索“C ++线程池”以查看此类任务队列的示例。