我创建了一个名为 EncodeThread 的自定义 QObject 类,如下所示:
class EncodeThread : public QObject {
Q_OBJECT
public:
void set(SWSL::Video* v, QStringList f, QDir vDir);
void run();
public slots:
void encode();
signals:
void encodeProgress(int i);
private:
SWSL::Video* video;
QStringList files;
QDir videoDir;
};
显而易见,该类用于使用外部库对视频进行编码。 Encode() 包含实际的编码例程,run() 是我在故障排除时添加的一个函数,尽管它显然不起作用:
void EncodeThread::run() {
if (currentThread() != this) {
// caller is in different thread.
QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
}
else {
encode();
}
}
问题是当我在 EncodeThread 实例上使用 QThread 和 moveToThread() 函数时,即似乎什么也没有发生。不写入任何数据,并且实例永远不会发出应将编码文件保存到磁盘的信号。
encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
thread.start();
以上就是整个设置的启动方式。 EncThread 和线程变量在 MainWindow 类中声明。在尝试使用信号从主线程调用encode()并且QMetaObject失败后,我已经使EncodeThread的set()函数调用encode()。
我对线程并不陌生,曾经使用过本机 Windows 和 Linux 线程,以及各种跨平台实现的线程,但 QThreads 似乎确实让我感到困惑。任何建议都非常受欢迎:)
I have created a custom QObject class called EncodeThread, which looks as follows:
class EncodeThread : public QObject {
Q_OBJECT
public:
void set(SWSL::Video* v, QStringList f, QDir vDir);
void run();
public slots:
void encode();
signals:
void encodeProgress(int i);
private:
SWSL::Video* video;
QStringList files;
QDir videoDir;
};
As may be obvious, this class is used for encoding a video using an external library. Encode() contains the actual encoding routine, run() is a function I added while troubleshooting, though it's obviously non-functional:
void EncodeThread::run() {
if (currentThread() != this) {
// caller is in different thread.
QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
}
else {
encode();
}
}
The problem is when I use a QThread and the moveToThread() function on the EncodeThread instance, namely that nothing seems to happen. No data is written, and the instance never emits the signal which should save the encoded file to disk.
encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
thread.start();
The above is how the whole setup is started. EncThread and thread variables are declared in the MainWindow class. I have made the set() function of EncodeThread call encode() after attempts to call encode() from the main thread using signals and QMetaObject failed.
I'm not new to threading, having used native Windows and Linux threads, as well as those of various cross-platform implementations, but QThreads really seem to baffle me. Any suggestions are more than welcome :)
发布评论
评论(3)
可能为时已晚,无法为您提供任何帮助,但这里有一个小演示程序,可以让
EncoderThread
类发挥作用。它可能与您的设计不太相符(您的问题只有片段),但它演示了在自己的线程上运行一个对象实例,并通过信号/槽在不同的线程上连接两个对象以使它们进行通信:Probably way to late to be any help to you, but here's a little demo program that puts an
EncoderThread
class to work. It probably doesn't quite mesh with your design (which your question only had fragments of), but it demonstrates running an object instance on its own thread and wiring 2 objects on different threads via signals/slots to let them communicate:您必须派生
QThread
,而不是QObject
。 run()方法是QThread
的抽象方法。You must derive
QThread
, notQObject
. run() method is an abstract method ofQThread
.对于未来的程序员,我添加这个答案。 Qt 中通常有 3 种多线程方法。 低级别, 重用(让说中级) 和 高级别。
低级别还包括两种不同的方法。在低级别中,您可以继承 QThread 类并提供要在
void QThread::run() 覆盖;
。在驱动类上调用QThread::start()
后,run
中的代码将执行。Qt 中低级多线程的另一种方法是中继 Qt 的事件循环。通过这种方式,您可以创建一个由
QObject
驱动的类,而不一定是由QThread
驱动,然后使用 QThread 中。 href="https://doc.qt.io/qt-5/qobject.html#moveToThread" rel="nofollow noreferrer">这个。之后,您将在该QThread
对象上调用start()
(此 QThread 对象是QThread
类型的对象。您没有在这里创建QThread
子类。我认为这是您在代码中误解的地方。在
QThread
对象上调用start()
后,其事件循环将在另一个线程中启动,并从代码中连接到QObject
只要您不使用Qt::DirectConnection
作为 这个。这两种方法各有优点和缺点。当子类化
QThread
并使用Qthread::run()
时,如果run
中的代码在while(true )
循环中,处理器的线程之一将始终被Qthread::run()
代码占用,而不是在程序中其他线程的线程池中。QObject::moveToThread()
方法对于大多数情况都很有用。但是,如果 QObject 驱动类的槽将被非常频繁地调用,例如每秒 100 或 1000 次,则由于可能传递给槽的参数,内存使用量会增加,并且其中一些信号可能永远不会被调用。到达插槽。For future programmers I'm adding this answer. There are generally 3 approaches to multi-threading in Qt. Low Level, Reusing(lets say Mid Level) and High Level.
Low level also includes two different approaches. In Low level you can Inherit QThread class and provide the code that you want to run in parallel inside
void QThread::run() override;
. After callingQThread::start()
on your drived class, code inrun
will execute.Another approach in Low Level Multi-threading in Qt is relaying on Qt's event loops. In this way you create a class that is drived from
QObject
, not necessarily fromQThread
and then move that class to a newQThread
with this. And after that you will callstart()
on thatQThread
object(this QThread object is an object of typeQThread
. You don't have to subclassQThread
here. Just instantiate one object. It is where I believe you misunderstood in your code).After calling
start()
on yourQThread
object, its event loop starts in another thread and signals from anywhere in your code that are connected to yourQObject
drived class's slots will run in that event loop in parallel as long as you don't useQt::DirectConnection
as last argument to this.These two approaches has their own benefits and drawbacks. When sub-classing
QThread
and usingQthread::run()
, if your code insiderun
is running inside awhile(true)
loop, one of your processor's threads will always be occupied withQthread::run()
code and not in the threadpool for other threads in your program.The
QObject::moveToThread()
approach is useful for most cases. But if theQObject
drived classe's slot is going to be called very frequently, like 100 or 1000 times per second, memory usage rises, due to possible arguments passed to the slot, and some of this signals may never reach the slot.