C/C++ Qt QThread线程组件的具体使用

时间:2023-01-13 15:46:36

QThread库是QT中提供的跨平台多线程实现方案,使用时需要继承QThread这个基类,并重写实现内部的Run方法,由于该库是基本库,默认依赖于QtCore.dll这个基础模块,在使用时无需引入其他模块.

实现简单多线程

QThread库提供了跨平台的多线程管理方案,通常一个QThread对象管理一个线程,在使用是需要从QThread类继承并重写内部的Run方法,并在Run方法内部实现多线程代码.

?
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <QCoreApplication>
#include <iostream>
#include <QThread>
 
class MyThread: public QThread
{
 
protected:
    volatile bool m_to_stop;
 
protected:
    // 线程函数必须使用Run作为开始
    void run()
    {
        for(int x=0; !m_to_stop && (x <10); x++)
        {
            msleep(1000);
            std::cout << objectName().toStdString() << std::endl;
        }
    }
 
public:
    MyThread()
    {
        m_to_stop = false;
    }
 
    // 用于设置结束符号为真
    void stop()
    {
        m_to_stop = true;
    }
 
    // 输出线程运行状态
    void is_run()
    {
        std::cout << "Thread Running = " << isRunning() << std::endl;
    }
 
    // 输出线程完成状态(是否结束)
    void is_finish()
    {
        std::cout << "Thread Finished = " << isFinished() << std::endl;
    }
 
};
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    // 定义线程数组
    MyThread thread[10];
 
    // 设置线程对象名字
    for(int x=0;x<10;x++)
    {
        thread[x].setObjectName(QString("thread => %1").arg(x));
    }
 
    // 批量调用run执行
    for(int x=0;x<10;x++)
    {
        thread[x].start();
        thread[x].is_run();
        thread[x].isFinished();
    }
 
    // 批量调用stop关闭
    for(int x=0;x<10;x++)
    {
        thread[x].wait();
        thread[x].stop();
 
        thread[x].is_run();
        thread[x].is_finish();
    }
 
    return a.exec();
}

向线程中传递参数

线程在执行前可以通过调用MyThread中的自定义函数,并在函数内实现参数赋值,实现线程传参操作.

?
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
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <QCoreApplication>
#include <iostream>
#include <QThread>
 
class MyThread: public QThread
{
protected:
    int m_begin;
    int m_end;
    int m_result;
 
    void run()
    {
        m_result = m_begin + m_end;
    }
 
public:
    MyThread()
    {
        m_begin = 0;
        m_end = 0;
        m_result = 0;
    }
 
    // 设置参数给当前线程
    void set_value(int x,int y)
    {
        m_begin = x;
        m_end = y;
    }
 
    // 获取当前线程名
    void get_object_name()
    {
        std::cout << "this thread name => " << objectName().toStdString() << std::endl;
    }
 
    // 获取线程返回结果
    int result()
    {
        return m_result;
    }
};
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    MyThread thread[3];
 
    // 分别将不同的参数传入到线程函数内
    for(int x=0; x<3; x++)
    {
        thread[x].set_value(1,2);
        thread[x].setObjectName(QString("thread -> %1").arg(x));
        thread[x].start();
    }
 
    // 等待所有线程执行结束
    for(int x=0; x<3; x++)
    {
        thread[x].get_object_name();
        thread[x].wait();
    }
 
    // 获取线程返回值并相加
    int result = thread[0].result() + thread[1].result() + thread[2].result();
    std::cout << "sum => " << result << std::endl;
 
    return a.exec();
}

QMutex 互斥同步线程锁

QMutex类是基于互斥量的线程同步锁,该锁lock()锁定与unlock()解锁必须配对使用,线程锁保证线程间的互斥,利用线程锁能够保证临界资源的安全性.

  • 线程锁解决的问题: 多个线程同时操作同一个全局变量,为了防止资源的无序覆盖现象,从而需要增加锁,来实现多线程抢占资源时可以有序执行.
  • 临界资源(Critical Resource): 每次只允许一个线程进行访问 (读/写)的资源.
  • 线程间的互斥(竞争): 多个线程在同一时刻都需要访问临界资源.
  • 一般性原则: 每一个临界资源都需要一个线程锁进行保护.
?
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
59
60
61
62
63
64
65
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex>
 
static QMutex g_mutex;      // 线程锁
static QString g_store;     // 定义全局变量
 
class Producer : public QThread
{
protected:
    void run()
    {
        int count = 0;
 
        while(true)
        {
            // 加锁
            g_mutex.lock();
 
            g_store.append(QString::number((count++) % 10));
            std::cout << "Producer -> "<< g_store.toStdString() << std::endl;
 
            // 释放锁
            g_mutex.unlock();
            msleep(900);
        }
    }
};
 
class Customer : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            g_mutex.lock();
            if( g_store != "" )
            {
                g_store.remove(0, 1);
                std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
            }
 
            g_mutex.unlock();
            msleep(1000);
        }
    }
};
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    Producer p;
    Customer c;
 
    p.setObjectName("producer");
    c.setObjectName("curstomer");
 
    p.start();
    c.start();
 
    return a.exec();
}

QMutexLocker是在QMutex基础上简化版的线程锁,QMutexLocker会保护加锁区域,并自动实现互斥量的锁定和解锁操作,可以将其理解为是智能版的QMutex锁,该锁只需要在上方代码中稍加修改即可.

?
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
#include <QMutex>
#include <QMutexLocker>
 
static QMutex g_mutex;      // 线程锁
static QString g_store;     // 定义全局变量
 
class Producer : public QThread
{
protected:
    void run()
    {
        int count = 0;
 
        while(true)
        {
            // 增加智能线程锁
            QMutexLocker Locker(&g_mutex);
 
            g_store.append(QString::number((count++) % 10));
            std::cout << "Producer -> "<< g_store.toStdString() << std::endl;
 
            msleep(900);
        }
    }
};

互斥锁存在一个问题,每次只能有一个线程获得互斥量的权限,如果在程序中有多个线程来同时读取某个变量,那么使用互斥量必须排队,效率上会大打折扣,基于QReadWriteLock读写模式进行代码段锁定,即可解决互斥锁存在的问题.

QReadWriteLock 读写同步线程锁

该锁允许用户以同步读lockForRead()或同步写lockForWrite()两种方式实现保护资源,但只要有一个线程在以写的方式操作资源,其他线程也会等待写入操作结束后才可继续读资源.

?
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QMutex>
#include <QReadWriteLock>
 
static QReadWriteLock g_mutex;      // 线程锁
static QString g_store;             // 定义全局变量
 
class Producer : public QThread
{
protected:
    void run()
    {
        int count = 0;
 
        while(true)
        {
            // 以写入方式锁定资源
            g_mutex.lockForWrite();
 
            g_store.append(QString::number((count++) % 10));
 
            // 写入后解锁资源
            g_mutex.unlock();
 
            msleep(900);
        }
    }
};
 
class Customer : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            // 以读取方式写入资源
            g_mutex.lockForRead();
            if( g_store != "" )
            {
                std::cout << "Curstomer -> "<< g_store.toStdString() << std::endl;
            }
 
            // 读取到后解锁资源
            g_mutex.unlock();
            msleep(1000);
        }
    }
};
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    Producer p1,p2;
    Customer c1,c2;
 
    p1.setObjectName("producer 1");
    p2.setObjectName("producer 2");
 
    c1.setObjectName("curstomer 1");
    c2.setObjectName("curstomer 2");
 
    p1.start();
    p2.start();
 
    c1.start();
    c2.start();
 
    return a.exec();
}

QSemaphore 基于信号线程锁

信号量是特殊的线程锁,信号量允许N个线程同时访问临界资源,通过acquire()获取到指定资源,release()释放指定资源.

?
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <QCoreApplication>
#include <iostream>
#include <QThread>
#include <QSemaphore>
 
const int SIZE = 5;
unsigned char g_buff[SIZE] = {0};
 
QSemaphore g_sem_free(SIZE); // 5个可生产资源
QSemaphore g_sem_used(0);    // 0个可消费资源
 
// 生产者生产产品
class Producer : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            int value = qrand() % 256;
 
            // 若无法获得可生产资源,阻塞在这里
            g_sem_free.acquire();
 
            for(int i=0; i<SIZE; i++)
            {
                if( !g_buff[i] )
                {
                    g_buff[i] = value;
                    std::cout << objectName().toStdString() << " --> " << value << std::endl;
                    break;
                }
            }
 
            // 可消费资源数+1
            g_sem_used.release();
 
            sleep(2);
        }
    }
};
 
// 消费者消费产品
class Customer : public QThread
{
protected:
    void run()
    {
        while( true )
        {
            // 若无法获得可消费资源,阻塞在这里
            g_sem_used.acquire();
 
            for(int i=0; i<SIZE; i++)
            {
                if( g_buff[i] )
                {
                    int value = g_buff[i];
 
                    g_buff[i] = 0;
                    std::cout << objectName().toStdString() << " --> " << value << std::endl;
                    break;
                }
            }
 
            // 可生产资源数+1
            g_sem_free.release();
 
            sleep(1);
        }
    }
};
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
 
    Producer p1;
    Customer c1;
 
    p1.setObjectName("producer");
    c1.setObjectName("curstomer");
 
    p1.start();
    c1.start();
 
    return a.exec();
}

到此这篇关于C/C++ Qt QThread线程组件的具体使用的文章就介绍到这了,更多相关Qt QThread线程使用内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/LyShark/p/15555343.html