从另一个线程调用一个函数

时间:2014-04-14 16:05:05

标签: c++ multithreading qt boost

我的应用程序在启动时有多个线程。我需要线程A才能强制线程B运行一个函数(也有参数。)我已经尝试在谷歌搜索但找不到我需要的东西,很多堆栈溢出文章没有似乎与我正在做的事情有关。我不确定我是否只是使用了错误的术语,也许这就是为什么我无法找到所需信息的原因。如果在他们的线程库中有一个选项,我可以使用Boost,如果有,如果你可以指向我一些示例代码的方向,我可以看看我需要什么。我的应用程序也已经使用了QT,虽然我从未使用过QT线程库,所以我也不知道它是否包含这个。

基本上我需要做的就是这个。

//Thread A
void ThreadA()
{
   //Do work to get data
   //Pass Data to another function, and have thread B run it.
   ThreadB.Run(data,arg2,arg3);
}

3 个答案:

答案 0 :(得分:3)

没有办法明确地做到这一点。您可以在线程之间传输邮件,例如使用events,这将触发调用所需的方法。但是目标线程必须处于循环中,等待消息。这是你可以强制线程进入另一个子程序的唯一方法。

抽象示例:

// in ThreadB [the target thread]

std::vector<Message> messages;
bool wait_message;

// ...

while(wait_message) {
    if(messages.size() > 0) {
        // process messages
    }
}

// ...

另一个主题是:

// in ThreadA

// ... 

messages.push_back(Message("call_my_method", some_data));

// ... 

班级Message(仅举例):

class Message {
private:
    std::string _what;
    void* _data;

public:
    Message(const std::string& what, void* data) : _what(what), _data(data) { }
    Message(const Message& inst) : _what(inst._what), _data(inst._data) { }

    const std::string& what() const { return _what; }
    void* data() const { return _data; }
};

仅对于函数调用,您可以使用std::functionstd::bind并仅传输回调,该回调会为您的消息提供一些固定签名(例如void(void))。

答案 1 :(得分:0)

我可以使用metaobject系统。但要注意后果。 只需看一下这篇博客文章(特别是评论中的MACRO部分) - &gt; click me 几年前我为一个项目偷了这个部分并喜欢它(但你必须真正了解你在做什么以及Qt如何处理这个电话)

您必须定义以下MACRO并根据需要扩展最后一部分:

// HELPER MACROS (from
// Just a helper macro:
#define NO_RETURN_VALUE

// This does the real work:
#define THREAD_MAGIC(targetThread, returnValue, args)     \
if(QThread::currentThread() != targetThread->thread())                     \
{                                                                \
    QString slotName = __FUNCTION__;                             \
    slotName.remove(QRegExp("^.*::"));                           \
    bool ret = metaObject()->invokeMethod(this,                  \
            qPrintable(slotName), Qt::QueuedConnection,          \
            args.count() >=  1 ? args[0] : QGenericArgument(0),  \
            args.count() >=  2 ? args[1] : QGenericArgument(0),  \
            args.count() >=  3 ? args[2] : QGenericArgument(0),  \
            args.count() >=  4 ? args[3] : QGenericArgument(0),  \
            args.count() >=  5 ? args[4] : QGenericArgument(0),  \
            args.count() >=  6 ? args[5] : QGenericArgument(0),  \
            args.count() >=  7 ? args[6] : QGenericArgument(0),  \
            args.count() >=  8 ? args[7] : QGenericArgument(0),  \
            args.count() >=  9 ? args[8] : QGenericArgument(0),  \
            args.count() >= 10 ? args[9] : QGenericArgument(0)); \
    if(!ret)                                                     \
    {                                                            \
        qFatal(qPrintable(__FUNCTION__ +                         \
          QString(" Could not call QMetaObject::invokeMethod(). " \
          "Check your argument list quantity and types.")));     \
    }                                                            \
    return returnValue;                                          \
 }

#define MAKE_THREAD_SAFE_0(TargetThread, returnValue)                \
    do {                                                         \
    QList<QGenericArgument> args;                                \
    THREAD_MAGIC(TargetThread, returnValue, args);    \
    } while (0);                                                  \


   #define THREAD_MAGIC_1(TargetThread, returnValue, ArgType1, ArgName1)         \
    do {                                                         \
    QList<QGenericArgument> args = QList<QGenericArgument>() <<  \
        Q_ARG(ArgType1, ArgName1);                               \
    THREAD_MAGIC(TargetThread, returnValue, args);    \
    } while (0);
                                                   \

#define THREAD_MAGIC_2(TargetThread, returnValue, ArgType1, ArgName1, ArgType2, ArgName2) \
    do {                                                         \
    QList<QGenericArgument> args = QList<QGenericArgument>() <<  \
        Q_ARG(ArgType1, ArgName1) <<                             \
        Q_ARG(ArgType2, ArgName2);                               \
    THREAD_MAGIC(TargetThread, returnValue, args);    \
    } while (0);

现在你必须实现你的功能,例如。

void ThreadClass::fn(const QString& user_, const QString& pwd_)
{
  THREAD_MAGIC_2(this, NO_RETURN_VALUE, QString, user_, QString, pwd_);
  // ... implementation of the function
}

正如我已经说过的那样:这不是我的想法 - 归功于Dave Smith。

答案 2 :(得分:0)

我让它在 R 中工作。R 有 environment()。因此,您必须使用 future 或 promise 在不同的环境中执行。我认为环境是线程相关的,不确定完整的机制,但未来的对象将执行并返回分配给它的 value()。