线程调用回调时修改QObject的访问冲突

时间:2014-02-09 20:15:22

标签: c++ multithreading qt boost

我的解决方案是第二次更新

我写了一个类,它本质上是一个无限循环,它对网络事件作出反应。这在控制台应用程序中运行良好 我现在试图在Qt GUI应用程序中使用所述类。该窗口只包含一个QPlainTextEdit(以及一个尚未使用的QLineEdit),我希望我的类能够在控制台上输出它通常输出的内容。
为此,我创建了一个回调函数(在bot类中称为outputLine),调用plainTextEdit.appendPlainText并将其提供给我的类,以便使用boost::functionboost::bind使其发挥作用。

当在此处调用回调函数时(bot类源文件)发生访问冲突:

char outputData[MAXDATASIZE];
iResult = recv(s, receive_buf, MAXDATASIZE, 0);
if (iResult > 0){
   numbytes = iResult;
   receive_buf[numbytes]='\0';
   sprintf(outputData, "%s: <<< %s", time_now(), receive_buf); 
   outputLine(std::string(outputData));

有趣的是,这不会导致访问冲突:

char temp[100];
sprintf(temp, "test %i", someInteger);
outputLine(temp);

如果我注释掉appendPlainText(t)行(参见下一个代码块),可以防止访问冲突,如果我这样做,一切正常(我通过检查机器人连接到的IRC服务器确认了这一点) :它加入频道并回答我的命令。)

以下是Qt源文件中的相关代码:

void QtTigerAutomaton::outputLine(std::string t){
    ui.plainTextEdit->appendPlainText(t.c_str());
}

QtTigerAutomaton::QtTigerAutomaton(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
    bot.setupBot("NICK somenick\r\n", "USER guest host server :some name\r\n", 
                 boost::bind(&QtTigerAutomaton::outputLine, this, _1));
}
void QtTigerAutomaton::onConnectClick(){
    botThread = new boost::thread(boost::bind(&IrcBot::start, &bot));
}

这是来自bot类的(希望)相关代码:
头文件:

typedef boost::function<void (std::string)> callbacktype;
/* ... */
callbacktype outputLine; //outputLine is assigned in setupBot

导致此访问冲突的原因是什么?如何阻止它?

PS:关于如何在Qt中显示机器人类输出的更好解决方案当然也非常受欢迎。我的目标是能够使用其使用我之前使用的控制台应用程序格式的GUI发送我的机器人命令。

更新

感谢答案,我现在认为问题是QWidgets等不是线程安全的,因此我将我的机器人转换为QObject,现在正尝试使用信号/插槽机制,如下所示:

在QtTigerAutomaton的构造函数中,我添加了

connect(&bot, SIGNAL(bot.outputSignal(const QString)), this, 
        SLOT(onOutputNeeded(const QString)));`

我意识到我可以直接使用ui.plainTextEdit->appendPlainText(const QString),但我希望能够更好地控制调试目的。

更相关的代码:

/* IrcBot.h */
public:
void testLine(){
    emit outputSignal("testing");
};
signals:
    void outputSignal(const QString);

然而,调用bot.testLine()什么都不做。我错误地使用了连接功能,或者我的错误是什么?

更新

connect语句的正确语法是
connect(&bot, SIGNAL(outputSignal(const QString)), this, SLOT(onOutputNeeded(const QString))); 它现在似乎确实有效。

问题的解决方案确实是使用信号/插槽机制,这显然比回调函数更优雅,它确实有效。谢谢大家的帮助!

这是一步一步:

将我的IrcBot类转换为QObject类并添加了要发出的信号:

#include <qobject.h>

class IrcBot : public QObject
{
    Q_OBJECT

/* ... */

signals:
    void outputSignal(const QString);

像这样连接信号:

connect(&bot, SIGNAL(outputSignal(const QString)), ui.plainTextEdit, 
        SLOT(appendPlainText(const QString)));
每当产生一些输出时,

发出信号如下:

emit outputSignal("some text"); //or various ways to generate output QStrings

现在,没有发生访问冲突,文本显示在我希望的plainTextEdit中。

PS:有没有办法将我的问题标记为现在的答案?由于我不能回答我自己的问题,我不知道如何:x我是新来的。

0 个答案:

没有答案