C++ 如何在C++;?

C++ 如何在C++;?,c++,multithreading,C++,Multithreading,有没有可能在给定线程ID的特定线程上调用函数?我目前在一个不同的线程 您需要目标线程的合作;例如,目标线程必须执行一个循环,在循环的顶部等待某种消息框。通过该消息框,您可以给它一条消息,其中包含要调用的函数和要使用的参数。通过相同的机制,函数可以生成包含调用结果的应答 但是你不能让运行任意代码的随机线程调用你的函数。虽然,永远不要说永远。有一些技巧,例如,异步POSIX信号等:向线程发送信号,线程检查一些数据,告诉它调用函数。这是混淆的限制,什么可以安全地做了一个信号处理器 在调试器中,您可以停

有没有可能在给定线程ID的特定线程上调用函数?我目前在一个不同的线程

您需要目标线程的合作;例如,目标线程必须执行一个循环,在循环的顶部等待某种消息框。通过该消息框,您可以给它一条消息,其中包含要调用的函数和要使用的参数。通过相同的机制,函数可以生成包含调用结果的应答

但是你不能让运行任意代码的随机线程调用你的函数。虽然,永远不要说永远。有一些技巧,例如,异步POSIX信号等:向线程发送信号,线程检查一些数据,告诉它调用函数。这是混淆的限制,什么可以安全地做了一个信号处理器


在调试器中,您可以停止所有线程,然后“切换”到特定线程,并在其上下文中计算表达式,包括函数调用。这也是一种不适合集成到生产代码中的方法;您不知道停止的线程处于何种状态才能在该线程中安全可靠地执行任何操作。

一种可能的解决方案是使工作线程基于任务(函数)执行,即使用容器存储希望工作线程执行的函数,工作线程的任务是执行容器中的函数

这里有一个例子,希望能有所帮助

#include <iostream>
#include <list>
#include <functional>
#include <thread>
#include <mutex>
#include <atomic>
#include <condition_variable>

using namespace std;

void foo() {
    cout << "foo() is called" << endl;
}

template<typename T>
class TaskQueue {
    public:
        void enqueue(T&& task) {
            unique_lock<mutex> l(m);
            tasks.push_back(move(task));
            cv.notify_one();
        }
        bool empty() { unique_lock<mutex> l(m); return tasks.empty(); }
        void setStop() { stop = true; unique_lock<mutex> l(m); cv.notify_one(); }
        void run() {
            T t;
            while (!stop) {
                {
                    unique_lock<mutex> l(m);
                    cv.wait(l, [&] {return !tasks.empty() || stop;});
                    if (!tasks.empty()) {
                        t = move(tasks.front());
                        tasks.pop_front();
                    }
                    else 
                        return;
                }
                t();
            }
        }
    private:
        atomic<bool> stop = false;
        mutex m;
        condition_variable cv;
        list<T> tasks;
};

int main() {
    TaskQueue<function<void(void)>> taskq;
    thread t(&TaskQueue<function<void(void)>>::run, &taskq);
    taskq.enqueue(foo);
    taskq.enqueue(foo);
    taskq.enqueue(foo);
    while (!taskq.empty()) {}
    taskq.setStop();
    t.join();
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
void foo(){

不能确定。您可以创建一个队列,并将要调用的函数放在那里,让目标线程读取队列并执行函数。某些框架内置了对它的支持,如Windows。@TedLyngmo您能详细说明一下吗?提前谢谢。您在这里有一些选项:。@Maxim Egorushkin您提到的帖子似乎是为了编辑原始代码,我不理解您在没有上下文的情况下对该帖子的具体评论(令人困惑的是,OP声称死锁仍然发生在最后一条评论中)。也许用这个例子更容易解释你的评论。@Maxim Egorushkin终于想出了一种方法来阅读那篇文章的原始代码,错误很简单——终止标志没有在条件变量等待条件中检查,而只是在外部循环中检查,肯定有竞争条件。这就是不过,这里不是这样,你能详细说明一下我们如何在这段代码中获得死锁吗?我还没有碰我的代码:-)我现在明白了,当保持互斥锁时,你确实要检查
stop
。这使得使用
std::atomic
作为stop标志是不必要的,因为你无论如何都要锁定互斥锁以发出信号。@Maxim Egorushkin请注意
t();
是在锁的作用域之外执行的,这取决于用例,您可能希望在获取互斥锁之前便宜地检查终止标志,这可能会导致与生产者线程的争用。我的代码的要点是说明如何实现任务队列,我将让它来决定琐碎的细节。我不认为终止时不必获取互斥锁是一个有意义的优化,您可以测量其效果。此外,根据选中
stop
的位置,它要么从队列中获取项目,要么不一致行为。