Qt学习之线程的使用(三)–循环调用两个线程(信号量)备忘

  • Post author:
  • Post category:其他

例子

创建两个线程,让两个线程先后运行,一秒只能有一个线程在运行,一个线程在运行时另一个线程处于阻塞状态,两个线程交替运行。

思路

利用信号量来做,两个线程两个信号量,开始时两个信号量都是0,当信号量为0时,继续获取也就是-1操作时,就会阻塞,所以假设有AB两个线程,每秒都让信号量-1,刚开始先让A 的信号量+1,那么第一秒只有A会运行,运行之后给B的信号量+1,第二秒A为0会阻塞,B为1会执行,一秒后A的信号量+1…依次循环,实现对AB线程的循环调用。

代码

用到的信号量 QSemaphore

这里对信号进行封装,使得一个变量可以控制两个信号量,并且使用单例模式,避免传递参数。

mythread.h (自定义线程函数 继承自QThread)

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>
#include "semaphone.h"

class mythread : public QThread
{
    Q_OBJECT
public:
    mythread(QString name,QObject * parent = 0);

private:
    QString name;

protected:
    //重写线程run函数
    virtual void run();

signals:
    void sendmsg(QString);
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"

mythread::mythread(QString name, QObject *parent):
    name(name),
    QThread(parent)
{
    semaphone *sem = semaphone::getInstance();
    if(name =="A"){
        sem->s1release();//先把线程1的信号量变成1
    }
}

void mythread::run()
{
    //单例获取信号量
    semaphone *sem = semaphone::getInstance();
    while(1){
        //如果调用该线程的是A 那么请求A 否则请求B
        if(name == "A"){
            sem->s1acquire();
        }else{
            sem->s2acquire();
        }
        //发送信号
        emit sendmsg(name);
        //睡眠1s
        this->sleep(1);
        //如果调用的是线程A 那么给线程B的信号量+1 下次就会调用线程B
        if(name == "A"){
            sem->s2release();
        }else{
            sem->s1release();
        }
    }
}

semaphone.h (自定义信号函数 )

#ifndef SEMAPHONE_H
#define SEMAPHONE_H

#include <QWidget>
#include <QObject>
#include <QSemaphore>

class semaphone
{
private:
    semaphone();
    static semaphone *instance;
    QSemaphore s1;//信号量s1用来控制线程A
    QSemaphore s2;//信号量s2用来控制线程B
public:
    static semaphone *getInstance(); //单例模式
    void s1acquire();//请求S1 -1
    void s1release();//释放S1 +1
    void s2acquire();//请求S2 -1
    void s2release();//释放S2 +1
};

#endif // SEMAPHONE_H

semaphone.cpp

#include "semaphone.h"

semaphone::semaphone()
{

}

semaphone *semaphone::getInstance()
{
    if(instance == NULL){
        instance = new semaphone;
    }
    return instance;
}

void semaphone::s1acquire(){
    s1.acquire();
}

void semaphone::s1release(){
    s1.release();
}

void semaphone::s2acquire(){
    s2.acquire();
}

void semaphone::s2release(){
    s2.release();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include "mythread.h"

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    Ui::Widget *ui;
    //两个线程指针
    mythread *t1;
    mythread *t2;

public slots:
    void rcvmsg(QString name);
};

#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    //线程初始化
    t1 = new mythread("A",this);
    t2 = new mythread("B",this);
    //线程开始
    t1->start();
    t2->start();
    //连接信号槽
    QObject::connect(t1,SIGNAL(sendmsg(QString)),this,SLOT(rcvmsg(QString)));
    QObject::connect(t2,SIGNAL(sendmsg(QString)),this,SLOT(rcvmsg(QString)));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::rcvmsg(QString name)
{
    //在文本框中显示调用线程的名字
    ui->textEdit->append(name);
}

main.cpp

#include "widget.h"
#include <QApplication>
#include "semaphone.h"

//声明信号的单例
semaphone* semaphone::instance = NULL;

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

效果

请添加图片描述


版权声明:本文为weixin_43701705原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。