报错原因
我最近在做一个 Dns 测速软件,目前为止它长这样

而问题就出现在这里,这个进度条

我想实现的效果是每测试完一个 IP 就自动更新 Progress,代码是这样写到(最后几行)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
void DnsSpeedTester::RunPing(int num) {
int rowCount = model->rowCount();
QMutex mutex; // 用于保护对 model 的访问的互斥锁
QList<QFuture<void>> futures; // 用于跟踪并发任务的 futures
for (int row = 0; row < rowCount; ++row) {
QFuture<void> future = QtConcurrent::run([=, &mutex]() {
CPing P;
QModelIndex index = model->index(row, 0);
QVariant data = index.data(Qt::DisplayRole);
QString tmp_IP = data.value<QString>();
QByteArray temp = tmp_IP.toLatin1();
char* IP = temp.data();
// 使用互斥锁保护对 model 的访问
{
QMutexLocker locker(&mutex);
model->setData(model->index(row, 2), "测量中");
}
int delay = P.pings(IP, num);
// 使用互斥锁保护对 model 的访问
{
QMutexLocker locker(&mutex);
if(delay>999999){
model->setData(model->index(row, 2), "请求超时");
//将超时的设置字体为红色
QColor color = QColor(Qt::red);
model->setData(model->index(row,2), color, Qt::ForegroundRole);
}
else{
model->setData(model->index(row, 2), delay);
//同上字体染色
QColor color;
if (delay < 50) {
color = QColor(98, 151, 52);
} else if (delay < 100) {
color = QColor(255, 150, 63);
} else {
color = QColor(255, 73, 73);
}
model->setData(model->index(row,2), color, Qt::ForegroundRole);
}
}
qDebug() << "行:" << row << " IP:" << IP << " 延迟:" << delay;
});
futures.append(future); // 存储 future 以便后续监控
PingedIP++;
Progress=PingedIP/AllIP;
ui->progressBar->setValue(Progress*100);
}
|
可以看见我这里使用QtConcurrent::run
来防止线程阻塞,然后又尝试修改progressBar
的值,然后程序就直接崩溃了,而且 Debug 全是汇编和内存地址,啥也看不懂,后来才知道:
在 QtConcurrent::run 中使用了 lambda 表达式,该表达式默认建立在被捕获变量的副本上运行。在你的代码中,你在 lambda 表达式中访问了 ui 的成员,这是不被允许的,因为在另一个线程中操作 GUI 对象可能会导致线程冲突或其他异常。
解决方案
那么这种问题要怎么解决呢?
答案就是使用信号和槽机制,使修改操作在原 UI 线程中操作
一下是我的修改
首先在头文件中定义一个信号和槽
1
2
3
4
|
signals:
void updateProgressBarSignal(int value);
public slots:
void onUpdateProgressBar(int value);
|
由于我这里是要修改 progressbar 的值,所以要一个 int 类型的值,然后再源文件中实现该槽函数
1
2
3
4
|
void DnsSpeedTester::onUpdateProgressBar(int value)
{
ui->progressBar->setValue(value);
}
|
最后将原来是直接修改的部分,改为发送一个信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
QFuture<void> future = QtConcurrent::run([=, &mutex]() {
CPing P;
QModelIndex index = model->index(row, 0);
QVariant data = index.data(Qt::DisplayRole);
QString tmp_IP = data.value<QString>();
QByteArray temp = tmp_IP.toLatin1();
char* IP = temp.data();
// 使用互斥锁保护对 model 的访问
{
QMutexLocker locker(&mutex);
model->setData(model->index(row, 2), "测量中");
}
int delay = P.pings(IP, num);
PingedIP++;
Progress=PingedIP/AllIP;
emit updateProgressBarSignal(Progress*100);
qDebug()<<Progress*100;
// 使用互斥锁保护对 model 的访问
{
QMutexLocker locker(&mutex);
if(delay>999999){
model->setData(model->index(row, 2), "请求超时");
//将超时的设置字体为红色
QColor color = QColor(Qt::red);
model->setData(model->index(row,2), color, Qt::ForegroundRole);
}
else{
model->setData(model->index(row, 2), delay);
//同上字体染色
QColor color;
if (delay < 50) {
color = QColor(98, 151, 52);
} else if (delay < 100) {
color = QColor(255, 150, 63);
} else {
color = QColor(255, 73, 73);
}
model->setData(model->index(row,2), color, Qt::ForegroundRole);
}
}
|
这样再运行就不会崩溃了
更新预告
我的 DNS 测速软件也快要写完了,给大家看一下演示效果,开发进度 70%
{% video http://storage.live.com/items/F770018B695998C2!227:/2024-01-28 21-36-05.mp4 %}
开发进度
{% checkbox blue checked,异步测试延迟 %}
{% checkbox blue checked,用户自定义测试次数 %}
{% checkbox blue checked, IP延迟排序 %}
{% checkbox blue checked, IP延迟染色 %}
{% checkbox 只显示测试通过/不通过%}
{% checkbox 右键直接设置为本机DNS %}
{% checkbox 界面UI美化 %}
{% checkbox 在线更新DNS列表 %}