我遇到的问题是,我决定实施QThreads
他们是应该的方式的基础上,大量文章:
http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
和问题在手是,由于算法是在单独运行QObject
(裹QThread
)。 我怎么能叫出类似Thread::Sleep
或不便..任何想法?
该软件的一个小说明。 基本上我的应用程序解决TSP
(旅行商问题)。 由于搜索一起去,这样可以节省所有的州在历史frames
。(如Visual帧)。 搜索算法将在一个线程中运行。 主线程与GUI操作。 再有就是Mediaplayer
像线程告诉Main
线程在屏幕上显示什么框架。 那么,这是否睡眠进来吗? 在GUI中有一个滑块,用户可以用它来快进或进入正常速度..这滑块通过信号插槽告诉给Mediaplayer
线程去更快或更慢。
我们所做的,基本上是这样的:(由记忆写的,因为我没有做我们的代码检查了这台计算机上)
class Sleeper : public QThread {
public:
void sleep(int ms) { QThread::sleep(ms); }
};
void sleep(int ms);
// in a .cpp file:
static Sleeper slp;
void sleep(int ms) {
slp.sleep(ms);
}
关键是, QThread::sleep
功能导致调用线程睡眠,而不是由所代表的threaf QThread
实例。 所以只要创建一个通过自定义调用它的包装QThread
子类。
不幸的是,QThread的是一个烂摊子 。 该文件告诉你错误地使用它。 一些博客文章,因为你发现,告诉你一个更好的方式来做到这一点,但你不能调用类的函数sleep
, 它本来就不应该摆在首位受保护的螺纹件 。
而最重要的,甚至不管你使用的QThread哪种方式,它的设计模仿什么可能是最糟糕的线程API迄今为止所设想的是,Java之一。 相比于一些理智,喜欢boost::thread
,甚至更好, std::thread
,它的臃肿,过于复杂和不必要很难使用和需要的样板代码数量惊人。
这确实是其中的Qt团队搞砸了的地方之一。 重要时刻。
答案很简单:你不应该在异步阻拦,运行至完成代码-在每一个事件处理程序,并位实施QObject
是应该做的工作,并返回,尽快。 它不应该做任何形式的忙等待或睡眠。 对于沿着这条线以上的咆哮,看到米罗萨梅克的我恨的RTOS 。
对于从上面的跟随更好的实现,看到这个答案,而不是 。 下面跟随宏观弄虚作假最好是留给坚持下的可怜的灵魂
我已经把它贴的如何做到这一点从视图的代码做什么点至少以正确的方式的例子。 如果你想要一个真正的实现,看起来没有比进一步加速的无堆叠协同程序 。
宏权谋是语法糖 -这使得该技术更可口(升压的确它比我在下面做的)。 无论您是使用宏或明确地写出来的方法,就是给你。 语法是不是有什么声称是这样做的“正确的方式”。 我不使用这样的预处理挂羊头卖狗肉的唯一一个 。 缺少的是支持嵌套函数调用,以及多个一内运行到完成执行的“线程” QObject
。 示例显示了只有一个“线”和异步函数调用只有一个级别的代码。 无堆栈的Python借此以合乎逻辑的结论。
如果以异步方式写它,你会看到所有的代码这种模式。 该SLEEP
宏是语法糖,以帮助使代码更容易理解。 有写它没有C ++哈克宏在句法不会霸道没有真正的清洁方式。 即使作为的C ++ 11的语言没有内置的产量支持。 见为什么不屈服加入的C ++ 0x? 。
这是真正的无阻塞的代码,你会看到周期定时器事件触发,而你是“睡着了”。 请注意,这个合作多任务比线程低得多的开销/进程切换由操作系统来完成。 还有就是为什么16位Windows应用程序代码是这样写的一个原因:它执行得很好,即使是在微薄的硬件。
请注意,此代码不需要 QThread
,实际上不使用QThread
,但如果你的对象移动到高优先级的线程,延迟将具有较低的传播。
Qt的定时器实现是足够聪明的降低Windows上的计时器滴答周期,如果周期是“短”。 您可以使用特定于平台的代码,我在下面展示,但应劝阻。 Qt的5,你只需启动Qt::PreciseTimer
计时器。 请注意,预装Windows 8系统,你的交易关闭功耗和性能略高内核开销在这里。 Windows 8中,OS X(XNU)和现代Linux是滴答,不从这样的性能质量的损失。
我应该承认,从清澈的预处理器滥用方向与##和__LINE__(令牌串联与定位宏)创造C代码宏 。
类似于SLEEP()
宏,你也可以实现一个GOTO()
宏,让你具有写在简单的有限状态机更容易遵循的阻塞代码风格,但都是在幕后异步的。 您可以有ENTER()
和LEAVE()
宏来实现的行动要在国家出入境等完成,但该代码可以看看完全像一个直线编码阻塞式的功能。 我发现它非常高效,而且更容易理解比没有任何语法糖衣代码。 因人而异。 最后,你会的东西的道路上的UML状态图,但较少的开销(包括运行时间和代码文本明智)比QStateMachine-based
实现。
下面是输出,星号是周期性的计时器滴答。
doing something
*
*
*
*
*
*
*
*
*
*
slept, a=10
*
*
*
*
*
slept, a=20
*
*
slept, a=30
*
slept, a=40
#sleep.pro
QT += core
QT -= gui
TARGET = sleep
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
//main.cpp
#ifdef Q_WS_WIN
#include <windows.h>
#endif
#include <cstdio>
#include <QtCore/QTextStream>
#include <QtCore/QObject>
#include <QtCore/QBasicTimer>
#include <QtCore/QTimer>
#include <QtCore/QCoreApplication>
QTextStream out(stdout);
// this order is important
#define TOKENPASTE2(x,y) x ## y
#define TOKENPASTE(x,y) TOKENPASTE2(x,y)
#define SLEEP(ms) sleep(ms, &SLEEPCLASS::TOKENPASTE(fun, __LINE__)); } void TOKENPASTE(fun, __LINE__)() {
class Object : public QObject
{
Q_OBJECT
#define SLEEPCLASS Object // used by the SLEEP macro
public:
Object() {
QTimer::singleShot(0, this, SLOT(slot1()));
periodic.start(100);
connect(&periodic, SIGNAL(timeout()), SLOT(tick()));
}
protected slots:
void slot1() {
a = 10; // use member variables, not locals
out << "doing something" << endl;
sleep(1000, &Object::fun1);
}
void tick() {
out << "*" << endl;
}
protected:
void fun1() {
out << "slept, a=" << a << endl;
a = 20;
SLEEP(500);
out << "slept, a=" << a << endl;
a = 30;
SLEEP(250);
out << "slept, a=" << a << endl;
a = 40;
SLEEP(100);
out << "slept, a=" << a << endl;
qApp->exit();
}
private:
int a; // used in place of automatic variables
private:
void sleep(int ms, void (Object::*target)()) {
next = target;
timer.start(ms, this);
}
void timerEvent(QTimerEvent * ev)
{
if (ev->timerId() == timer.timerId()) {
timer.stop(); (this->*next)();
}
}
QTimer periodic;
QBasicTimer timer;
void (Object::* next)();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Object o1;
#ifdef Q_WS_WIN
timeBeginPeriod(1); // timers will be accurate to 1ms
#endif
return a.exec();
}
#include "main.moc"
我同意jalf。 我有一个作为一种DBUS守护进程,需要收听消息永远线程。 两件事情提:
jalf有
void sleep(int ms) { QThread::sleep(ms); }
但这不是MILLISECONDS! 的QThread ::睡眠()只需要几秒钟。 此外,如果一个人采取这种方法,他还必须包括的lib的QThread无论如何,所以它可能是更容易只是使这样的呼吁:
QThread::sleep(seconds);
代码可以直接在。 这样,没有额外的头文件。 我跑了这一点,它也可以作为jalf解释。 (把调用线程睡觉。)
对于Qt的4.8.0(我使用的版本), QThread::sleep
, QThread::msleep
和QThread::usleep
已经公布,因此您可以只需直接调用它们。 在早期的Qt版本,他们是static protected
。
例如QThread::sleep(5); // sleep for 5 seconds
QThread::sleep(5); // sleep for 5 seconds