十三、QT多线程(QThread)
1、创建线程方法1:moveToThread
class Worker:public QObject
{
QOBJECT
public slot:
void doWork(const QString ¶meter){
QString result;
/* ..耗时或阻塞的操作.. */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
class Controller:public QObject
{
QOBJECT
// 创建线程对象
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
// Worker对象移动到线程中
worker->moveToThread(&workerThread);
// 当发送operate信号,dowork将在一个独立的线程中执行
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
// 开启
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
2、创建线程方法2:继承QThread,重写run函数(推荐)
class WorkerThread : public QThread
{
Q_OBJECT
// 线程的入口函数
void run() Q_DECL_OVERRIDE {
QString result;
/* 耗时或阻塞的操作 */
emit resultReady(result);
}
signals:
void resultReady(const QString &s);
};
void MyObject::startWorkInAThread()
{
// 创建线程对象
WorkerThread *workerThread = new WorkerThread(this);
connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
// 开启线程
workerThread->start();
}
3、退出线程
void QThread::exit(int returnCode = 0)
void QThread::quit() [slot]
4、等待线程
bool QThread::wait(unsigned long time = ULONG_MAX)
5、开启线程
void QThread::start(Priority priority = InheritPriority)
6、终止线程
void QThread::terminate()
// 设置线程是否允许被终止(默认:true,设置为false后线程不能被terminate()终止)
void QThread::setTerminationEnabled(bool enabled = true)
7、获取当前线程的句柄(ID)
Qt::HANDLE QThread::currentThreadId()
案例:多线程打印消息
工程名:Thread
类名:ThreadDialog
8、线程同步
1)互斥锁 QMutex
QMutex mutex;
mutex.lock(); // 加锁
mutex.unlock(); // 解锁
2)读写锁 QReadWriteLock
void QReadWriteLock::lockForRead(); // 加读锁
void QReadWriteLock::lockForWrite(); // 加写锁
3)信号量 QSemaphore
QSemaphore::QSemaphore(int n = 0); // 初始化资源个数为n
void QSemaphore::acquire(int n = 1);// 获取一个资源(p:信号量-1)
void QSemaphore::release(int n = 1);// 释放一个资源(v:信号量+1)
案例:生产者和消费者
问题:
1)生产者向仓库存放数据,但是如果生产的太快,将会把消费者还未读走的数据覆盖;
2)消费者从仓库中获取数据,但是如果消费者消费的太快,将会越过生产者,读走一些无效数据;
解决方法:
使用两个信号量,一个信号量(freeSpace)控制生产者,如果仓库满则等待;另一个信号量(usedSpace)控制消费者,如果仓库空则等待;
/* 生产者线程 */
while(1){
p(freeSpace)
// 生产一个产品并存放到仓库
v(usedSpace)
}
/* 消费者线程 */
while(1){
p(usedSpace)
// 从仓库中取出一个产品
v(freeSpace)
}
4)条件变量 QWaitCondition
QWaitCondition w; // 创建条件变量
w.wait(&mutex); // 让当前线程进入休眠,同时解锁
w.wakeAll(); // 唤醒所有等待的线程
w.wakeOne(); // 唤醒一个等待的线程
十四、QT网络编程
1、网络的协议层次(OSI七层)
层次 | 协议 | |
应用层 | HTTP、FTP、SMTP、POP3、DNS.. | |
表示层 | ||
会话层 | ||
传输层 | TCP、UDP | |
网络层 | IPv4、IPv6 | |
数据链路层 | 以太网 | |
物理层 |
扩展:
协议 | 全称 |
HTTP | 超文本传输协议(Hyper Text Transfer Protocol) |
FTP | 文件传输协议(File Transfer Protocol) |
SMTP | 简单邮件传输协议(Simple Mail Transfer Protocol) |
POP3 | 邮局协议版本3(Post Office Protocol - Version 3) |
DNS | 域名系统(Domain Name System) |
TCP | 传输控制协议(Transmission Control Protocol ) |
UDP | 用户数据报协议(User Datagram Protocol) |
2、回顾linux的socket编程
1)TCP编程
服务器:
a. 创建socket套接字:socket()
b. 准备服务器地址:struct sockaddr_in
c. 绑定bind()
d. 监听listen(sfd, 100)
e. 等待客户端的连接accept()
(开启子进程或子线程)
f. 通信:read()/write()
、recv()/send()
g. 关闭close()
客户端:
a. 创建socket套接字:socket()
b. 准备服务器地址:struct sockaddr_in
c. 向服务器发送连接请求:connect()
d. 通信:read()/write()
、recv()/send()
f. 关闭close()
2)UDP编程
服务器端:
a. 创建socket套接字socket()
b. 准备服务器地址struct sockaddr_in
c. 绑定bind()
d. 通信:recvfrom()/sendto()
e. 关闭
客户端:
a. 创建socket套接字:socket()
b. 准备服务器地址:struct sockaddr_in
c. 通信:read()/recvfrom()/sendto()
e. 关闭close()