QT 多线程 依次执行的问题

时间:2022-09-28 18:31:05
QT,编写一个多线程,即开启9个线程,这九个线程的ID分别为1,2,3,4,5,6,7,8,9,每个线程将自己的ID按顺序打印到屏幕上,要求结果必须按照1,2,3,4,5,6,7,8,9...依次类推
本人刚开始接触多线程,尝试写了段程序,但是结果不对,我用计数器每隔100毫秒执行一次显示:即
主线程代码:
QMutex mutex;
void MyClass::handleProcess(){
     QVector<QThread*> threads;
         m_timer = new QTimer(this);
connect(m_timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
m_timer->setTimerType(Qt::PreciseTimer);
for (int k = 0; k<3; k++){
QThread *imageThread = new QThread;
MyImage *myImage = new MyImage(k);
myImage->moveToThread(imageThread);
connect(this, SIGNAL(imageCreate()), myImage, SLOT(startImageCreate()));
threads.append(imageThread);
}
    m_timer->start(100);
}
void MyClass::onTimeOut(){
for (int i = 0; i<9; i++)
   threads[i]->start();
emit imageCreate();
}

子线程代码:
class MyImage : public QObject
{
Q_OBJECT
public:
explicit MyImage(int index = 0);
public slots :
void startImageCreate(int index);
private:
int index;
};
extern QMutex mutex;
MyImage::MyImage(int No) :QObject()
{
index = No  ;
}

void MyImage::startImageCreate(int index)
{
mutex.lock();
qDebug() << index  << " running..\n";
mutex.unlock();
}

各位大神,我的主要目的就是想依次的执行线程,请问怎么加互斥量才会解决这个问题呢,在线等,拜谢!

6 个解决方案

#1


多线程没法按照你的要求依次调用,如何调用系统会有一个调度策略,按照线程优先级或者系统资源使用率等来调度线程,你所能做的是保证你的代码在多线程环境下运行不出错,使用互斥量是为了保证锁住的代码在同一时间只有一个线程运行,而不会是多个线程同时运行该段代码导致结果出错。

#2


引用 1 楼 qqwangfan 的回复:
多线程没法按照你的要求依次调用,如何调用系统会有一个调度策略,按照线程优先级或者系统资源使用率等来调度线程,你所能做的是保证你的代码在多线程环境下运行不出错,使用互斥量是为了保证锁住的代码在同一时间只有一个线程运行,而不会是多个线程同时运行该段代码导致结果出错。


如果,这九个线程结束后,都会通过信号量-槽的方式调用主线程里的函数,也就是九个线程同时访问主线程里的响应函数,即使,我用vectro<int> vecTemp , 九个ID,分别存储数据到对应的vecTemp[ID]下,请问这种情况,我需要对主线程里的响应函数使用互斥量嘛?

#3


我给你发动了一下.相信应该可以理解.
没有使用锁,使用的信号量.它正好可以满足你的需求.



#include <QCoreApplication>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QObject
{
    Q_OBJECT
public:
    explicit MyImage(int index = 0);
public slots :
    void startImageCreate();
private:
    int index;
};
static QSemaphore sem(1);

MyImage::MyImage(int No) :QObject()
{
    index = No  ;
}

void MyImage::startImageCreate()
{
    sem.acquire(index); //获取资源,
    qDebug() << "index:" << index;
    sem.release(index+1);//释放多一个的资源,刚好可以,让下一个acquire获取成功.
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<QThread*> threads;
    for (int k = 1; k <= 9; k++) //从一开始.到9结束
    {
        QThread *imageThread = new QThread;
        MyImage *myImage = new MyImage(k);

        imageThread->start(); //启动线程
        myImage->moveToThread(imageThread);

        threads.append(imageThread);

        //用QTimer来触发槽,和连接一个信号再发出信号一个效果,都是Qt::QueuedConnection效果.
        QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
    }

    return a.exec();
}

#include "main.moc"

#4


引用 3 楼 n7zj0x8 的回复:
我给你发动了一下.相信应该可以理解.
没有使用锁,使用的信号量.它正好可以满足你的需求.



#include <QCoreApplication>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QObject
{
    Q_OBJECT
public:
    explicit MyImage(int index = 0);
public slots :
    void startImageCreate();
private:
    int index;
};
static QSemaphore sem(1);

MyImage::MyImage(int No) :QObject()
{
    index = No  ;
}

void MyImage::startImageCreate()
{
    sem.acquire(index); //获取资源,
    qDebug() << "index:" << index;
    sem.release(index+1);//释放多一个的资源,刚好可以,让下一个acquire获取成功.
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<QThread*> threads;
    for (int k = 1; k <= 9; k++) //从一开始.到9结束
    {
        QThread *imageThread = new QThread;
        MyImage *myImage = new MyImage(k);

        imageThread->start(); //启动线程
        myImage->moveToThread(imageThread);

        threads.append(imageThread);

        //用QTimer来触发槽,和连接一个信号再发出信号一个效果,都是Qt::QueuedConnection效果.
        QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
    }

    return a.exec();
}

#include "main.moc"


你好,这段代码是只执行一次的显示,即一次1到9的打印,如果想反复打印的话,是不是需要把QTimer::singleShot(0, myImage, SLOT(startImageCreate()));放入一个定时器响应函数中呢?

#5



#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.

#6


你好,这个确实能够实现依次显示,但是,我发现它是阻塞的方式,也就是只有等依次显示完成,才能启动主界面,是这样的,我的程序是,每个线程中保存的数据是图像,每次九个都执行完一次后,这些图像需要在主线程里显示出来,之后九个线程在继续保存新的图像,继续在主线程里显示,我改怎么修改这种阻塞的方式呢,多谢大神~

引用 5 楼 n7zj0x8 的回复:

#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.


引用 5 楼 n7zj0x8 的回复:

#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.

#1


多线程没法按照你的要求依次调用,如何调用系统会有一个调度策略,按照线程优先级或者系统资源使用率等来调度线程,你所能做的是保证你的代码在多线程环境下运行不出错,使用互斥量是为了保证锁住的代码在同一时间只有一个线程运行,而不会是多个线程同时运行该段代码导致结果出错。

#2


引用 1 楼 qqwangfan 的回复:
多线程没法按照你的要求依次调用,如何调用系统会有一个调度策略,按照线程优先级或者系统资源使用率等来调度线程,你所能做的是保证你的代码在多线程环境下运行不出错,使用互斥量是为了保证锁住的代码在同一时间只有一个线程运行,而不会是多个线程同时运行该段代码导致结果出错。


如果,这九个线程结束后,都会通过信号量-槽的方式调用主线程里的函数,也就是九个线程同时访问主线程里的响应函数,即使,我用vectro<int> vecTemp , 九个ID,分别存储数据到对应的vecTemp[ID]下,请问这种情况,我需要对主线程里的响应函数使用互斥量嘛?

#3


我给你发动了一下.相信应该可以理解.
没有使用锁,使用的信号量.它正好可以满足你的需求.



#include <QCoreApplication>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QObject
{
    Q_OBJECT
public:
    explicit MyImage(int index = 0);
public slots :
    void startImageCreate();
private:
    int index;
};
static QSemaphore sem(1);

MyImage::MyImage(int No) :QObject()
{
    index = No  ;
}

void MyImage::startImageCreate()
{
    sem.acquire(index); //获取资源,
    qDebug() << "index:" << index;
    sem.release(index+1);//释放多一个的资源,刚好可以,让下一个acquire获取成功.
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<QThread*> threads;
    for (int k = 1; k <= 9; k++) //从一开始.到9结束
    {
        QThread *imageThread = new QThread;
        MyImage *myImage = new MyImage(k);

        imageThread->start(); //启动线程
        myImage->moveToThread(imageThread);

        threads.append(imageThread);

        //用QTimer来触发槽,和连接一个信号再发出信号一个效果,都是Qt::QueuedConnection效果.
        QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
    }

    return a.exec();
}

#include "main.moc"

#4


引用 3 楼 n7zj0x8 的回复:
我给你发动了一下.相信应该可以理解.
没有使用锁,使用的信号量.它正好可以满足你的需求.



#include <QCoreApplication>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QObject
{
    Q_OBJECT
public:
    explicit MyImage(int index = 0);
public slots :
    void startImageCreate();
private:
    int index;
};
static QSemaphore sem(1);

MyImage::MyImage(int No) :QObject()
{
    index = No  ;
}

void MyImage::startImageCreate()
{
    sem.acquire(index); //获取资源,
    qDebug() << "index:" << index;
    sem.release(index+1);//释放多一个的资源,刚好可以,让下一个acquire获取成功.
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QVector<QThread*> threads;
    for (int k = 1; k <= 9; k++) //从一开始.到9结束
    {
        QThread *imageThread = new QThread;
        MyImage *myImage = new MyImage(k);

        imageThread->start(); //启动线程
        myImage->moveToThread(imageThread);

        threads.append(imageThread);

        //用QTimer来触发槽,和连接一个信号再发出信号一个效果,都是Qt::QueuedConnection效果.
        QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
    }

    return a.exec();
}

#include "main.moc"


你好,这段代码是只执行一次的显示,即一次1到9的打印,如果想反复打印的话,是不是需要把QTimer::singleShot(0, myImage, SLOT(startImageCreate()));放入一个定时器响应函数中呢?

#5



#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.

#6


你好,这个确实能够实现依次显示,但是,我发现它是阻塞的方式,也就是只有等依次显示完成,才能启动主界面,是这样的,我的程序是,每个线程中保存的数据是图像,每次九个都执行完一次后,这些图像需要在主线程里显示出来,之后九个线程在继续保存新的图像,继续在主线程里显示,我改怎么修改这种阻塞的方式呢,多谢大神~

引用 5 楼 n7zj0x8 的回复:

#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.


引用 5 楼 n7zj0x8 的回复:

#include <QCoreApplication>
#include <QEventLoop>
#include <QSemaphore>
#include <QTimer>
#include <QThread>
#include <QDebug>

class MyImage : public QThread
{
    Q_OBJECT
public:
    explicit MyImage(QSemaphore *sem, int index = 0) : sem(sem), index(index){}
    ~MyImage() { this->exit(); this->wait(); }

public slots :
    void startImageCreate()
    {
        sem->acquire(index);
        qDebug() << "index:" << index;
        sem->release(index+1);

        this->exit();
    }

private:
    QSemaphore *sem;
    int index;
};

class Process1_9
{
public:
    Process1_9() : sem(1){}
    ~Process1_9(){}

    void process()
    {
        QEventLoop loop;

        QVector<MyImage*> threads;
        for (int k = 1; k <= 9; k++)
        {
            MyImage *myImage = new MyImage(&sem, k);
            if (k == 9)
            {
                QObject::connect(myImage, SIGNAL(finished()), &loop, SLOT(quit()));
            }

            threads.append(myImage);

            myImage->start();
            myImage->moveToThread(myImage);

            QTimer::singleShot(0, myImage, SLOT(startImageCreate()));
        }

        loop.exec();

        qDeleteAll(threads);
    }

private:
     QSemaphore sem;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    for (int i = 0; i < 3; ++i)
    {
        Process1_9 p;
        p.process();

        qDebug() << "===times:" << i + 1;
        QEventLoop loop;
        QTimer::singleShot(1000, &loop, SLOT(quit()));
        loop.exec();
    }

    return a.exec();
}

#include "main.moc"



就是把1-9的执行再封装一下呀. 方式很多,我随便写的.你看着修改吧.