c++ - 通过 Qt 中的线程调用 Rust 库
问题描述
我正在为 Rust 库制作一个 Qt 前端,它公开了一个 C++ 函数,该函数阻止了它所在的执行线程,但允许传递一个回调函数以在两端之间进行通信。
所以我想到了使用 Qt 的线程技术让库在另一个线程上执行,并且我希望对 Rust 库进行尽可能少的修改。
这是我使用 QThreads 的方法:
后端.cpp:
typedef void(*callback_t)(void *,const char *);
extern "C" call_rust_library(const char *config, void *cb_data, callback_t cb);
template<typename T>
void call_wrapper(void *ptr, const char*data) {
(*static_cast<T*>(ptr))(data);
}
class BackEnd : public QObject {
Q_OBJECT
public slots:
void do_computations(ConfigObject *config) {
//...parse configuration from the frontend...
char* parsed_configuration;
BackEnd* backend = this;
auto callback = [backend](char* data) {
//...process obtained data from the library...
QString type,contents;
backend->emit send_message(type,contents);
}
call_rust_library(parsed_configuration,(void *)&callback,call_wrapper<decltype(callback)>);
}
signals:
void send_message(QString type, QString contents);
}
前端.cpp:
class FrontEnd : public QMainWindow {
Q_OBJECT
QThread thread;
ConfigObject *config;
public slots:
void process_message(QString type, QString contents) {
//...do GUI things with the message
}
private slots:
void on_request_start_thread() {
// called by a GUI event
BackEnd* backend = new BackEnd;
backend->moveToThread(&thread);
connect(&thread,&QThread::finished,backend,&QObject::deleteLater);
connect(this,&FrontEnd::run_thread,backend,&BackEnd::do_computations);
connect(backend,&BackEnd::send_message,frontend,&FrontEnd::process_message);
emit run_thread(config)
}
signals:
void run_thread(ConfigObject *config);
}
但是我有几个问题:
- 首先,后端没有任何内容被执行。如果我不将 BackEnd 对象移动到另一个线程,它似乎会运行所有东西,但会在系统库的某个地方崩溃(我最好的猜测是因为 Qt 禁止阻塞 GUI 线程和/或处理来自另一个线程的 GUI 函数)。
- Qt 如何能够中止 Rust 库执行线程?(通过关闭应用程序或用户单击按钮)Rust 库似乎没有公开任何机制来停止其执行,所以我想知道我是否必须对库进行修改以公开一个函数以中止它是什么正在做。
最近我发现这个示例存储库允许将 Qt 与 Rust 库绑定,但似乎没有深入研究多线程,并且可能需要将我的项目从 CMake 移植到 qmake。但据我了解,Rust 执行应该驻留在另一个线程中,所以我不确定它是如何在这里实现的。
解决方案
实现是正确的,除了我在函数thread->start()
结束时忘记了调用。on_request_thread()
崩溃是因为解析ConfigObject时出现问题,所以和线程的制作无关。
推荐阅读
- javascript - 非常简单的翻转在 Safari 中不起作用
- javascript - 为什么需要刷新页面才能进行身份验证?
- docker - 如何创建 Docker 运行时参数以在运行时将主机文件复制到容器中?
- php - 如何在 Lumen 6x 中实现默认 Laravel 重置密码
- go - Elasticsearch 7和golang找不到数据
- unix - 如何根据unix中file1的内容创建多个文件?file1 的 line1 到 newfile1 file1 的 line2 到 newfile2 等等
- python - 使用参数激活(源)python virtualenv 的 Bash 脚本
- html - 删除前一个元素后如何停止元素的移动?
- python - 如何在 Windows 中使用 Conda 安装`coincbc`
- python - 奇怪的性能结果——循环与列表理解和 zip()