不正确地终止线程?

Posted

技术标签:

【中文标题】不正确地终止线程?【英文标题】:Improperly terminating a thread? 【发布时间】:2016-04-20 16:58:22 【问题描述】:

我有一个正在并行化的 n 体模拟。我正在使用 QT,所以我有一个自定义 QObject 类,其中包含我已经并行化的过程。它由只处理线程的线程内的另一个 QObject 控制。问题是每次一个对象与另一个对象发生碰撞时,都必须停止所有线程,以便将它们删除,并使用不同的行星系统重新创建。

这里是线程处理类源码:

#include "threadhandler.h"
#include <QEventLoop>
#include "subprocess.h"
#include <QThread>
#include <iostream>
#include <vector>
#include <thread>
#include <chrono>

ThreadHandler::ThreadHandler(double scopeX, double scopeY)

int size = 100;
int idealNum = QThread::idealThreadCount();
int sizeForEach = size/idealNum;

for(int i = 0 ; i< idealNum ;i++)
   SubProcess* tempSub = new SubProcess(i*sizeForEach, (i+1)*sizeForEach, scopeX, scopeY);
   QThread* tempThread = new QThread;
   tempSub->moveToThread(tempThread);
   QEventLoop::connect(tempSub, SIGNAL(finished()), tempThread, SLOT(deleteLater()));
   QEventLoop::connect(tempThread, SIGNAL(started()), tempSub, SLOT(process()));
   QEventLoop::connect(tempThread, SIGNAL(finished()), tempSub, SLOT(deleteLater()));
   QEventLoop::connect(tempSub, SIGNAL(collided()), this,
                       SLOT(refactorObjects()));
   ThreadHandler::threads.push_back(tempThread);
   ThreadHandler::objects.push_back(tempSub);



void ThreadHandler::process()
std::cout << ThreadHandler::threads.size() << std::endl;
for(int i = 0; i < ThreadHandler::threads.size(); i++)
    std::cout << "starting " << i+1 << std::endl;
    ThreadHandler::threads.at(i)->start();



void ThreadHandler::refactorObjects()
SubProcess::condition = false;
std::this_thread::sleep_for(std::chrono::seconds(1));
for(int i = 0 ; i < ThreadHandler::threads.size() ; i++)
    ThreadHandler::threads.at(i)->terminate();

ThreadHandler::objects.clear();
SubProcess::sys.push_back(Body::collide(SubProcess::collidedAr.at(0), SubProcess::collidedAr.at(1)));
SubProcess::sys.erase(std::remove(SubProcess::sys.begin(), SubProcess::sys.end(),
                                  SubProcess::collidedAr.at(0)), SubProcess::sys.end());
SubProcess::sys.erase(std::remove(SubProcess::sys.begin(), SubProcess::sys.end(),
                                  SubProcess::collidedAr.at(1)), SubProcess::sys.end());

int idealNum = QThread::idealThreadCount();
int sizeForEach = SubProcess::sys.size() / idealNum;
for(int i = 0 ; i < idealNum ; i++)
    SubProcess* tempSub = new SubProcess(i*sizeForEach, (i+1)*sizeForEach);
    tempSub->moveToThread(ThreadHandler::threads.at(i));
    ThreadHandler::objects.push_back(tempSub);
    QEventLoop::connect(tempSub, SIGNAL(finished()), ThreadHandler::threads.at(i), SLOT(deleteLater()));
    QEventLoop::connect(ThreadHandler::threads.at(i), SIGNAL(started()), tempSub, SLOT(process()));
    QEventLoop::connect(ThreadHandler::threads.at(i), SIGNAL(finished()), tempSub, SLOT(deleteLater()));
    QEventLoop::connect(tempSub, SIGNAL(collided()), this,
                        SLOT(refactorObjects()));


for(int i = 0; i < idealNum; i++)
    ThreadHandler::threads.at(i)->start();

std::cout << "refactored" << std::endl;

这里是子流程源码:

#include "subprocess.h"
#include <iostream>

std::vector<Body> SubProcess::sys;
std::vector<Body> SubProcess::collidedAr;
double SubProcess::timeScale;
bool SubProcess::condition = true;


SubProcess::SubProcess(double start, double end, double scopeX, double scopeY)
for(int i = start; i< end; i++)
    SubProcess::sys.push_back(Body::createRandomBody(scopeX, scopeY));

this->start = start;
this->end = end;

SubProcess::SubProcess(double start, double end)
this->start = start;
this->end = end;


void SubProcess::process()
while(SubProcess::condition)
    for(int i = start; i < end ; i++)
        for(int j = 0; j < SubProcess::SubProcess::sys.size() ; j++)
            if(!(SubProcess::sys.at(i)==SubProcess::sys.at(j)))
                double F = Body::getForce(SubProcess::sys.at(i), SubProcess::sys.at(j));
                if (F!=-1)
                    double dX = SubProcess::sys.at(i).getX()-SubProcess::sys.at(j).getX();
                    double dY = SubProcess::sys.at(i).getY()-SubProcess::sys.at(j).getY();
                    SubProcess::sys.at(i).exertForce(-dY, -dX, F, timeScale);
                 else 
                    SubProcess::collidedAr.clear();
                    SubProcess::collidedAr.push_back(SubProcess::sys.at(i));
                    SubProcess::collidedAr.push_back(SubProcess::sys.at(j));
                    SubProcess::condition = false;
                    emit collided();
                
            
        
        SubProcess::sys.at(i).tick(timeScale);
    

emit finished();

每当我运行它时,它都能完美运行,直到我得到碰撞点:

starting 1
starting 2
starting 3
starting 4
refactored
refactored
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running

所以对我来说没有意义的是线程在重构过程开始时被删除,并且不会产生错误。但是由于某种原因,在新线程启动后,有些东西正在结束它们。我根本不知道这里发生了什么。我认为我不正确地处理和重新创建线程,应该有更好的方法来解决这个问题。

【问题讨论】:

【参考方案1】:

一般而言,终止正在运行的线程会导致未定义的行为(与在其他数据一致的状态下阻塞的线程相反)。您不应该终止线程。只需在子进程上执行deleteLater,它们就会自动处理掉自己。他们的线程不会受到影响。请参阅 this answer 了解为什么可以对其他线程中的对象调用 deleteLater

您应该保留一个线程池以供重用,无需重新创建它们。您甚至可以为此重复使用 QThreadQueue

默认的QThread 销毁是非常不安全的,如果可以的话,您应该使用a version without that deficiency。

【讨论】:

但是如果我对它们调用 deleteLater,那么我该如何重用它们呢?这不是删除它们吗?还是暂时停止? @user1563074 当然,您删除的是工作对象(子进程),而不是线程。 如果我不需要销毁/处置线程,那么为什么我需要一个更安全的销毁自定义线程类。另外,我已经更新了上面的代码,它仍然会产生同样的错误。 @user1563074 你会最终处理掉它们,我想:)

以上是关于不正确地终止线程?的主要内容,如果未能解决你的问题,请参考以下文章

关于tensorflow 的数据读取线程管理QueueRunner

Java并发编程:线程挂起恢复与终止的正确方法(含代码)

转: Java并发编程之三:线程挂起恢复与终止的正确方法(含代码)

如何正确的终止正在运行的子线程

如何正确终止 dll 中的挂起线程?

如何正确停止线程