一、簡介
為什么要用多線程讽膏?在音視頻領(lǐng)域主要是實(shí)現(xiàn)音視頻同步桨醋。實(shí)現(xiàn)了音視頻同步棚瘟,我們的播放器就基本上合格了。
多線程的好處主要是能使程序更加充分利用硬件(主要是CPU)的性能喜最。但是也存在相應(yīng)的隱患偎蘸,如果多線程管理不好,會(huì)出現(xiàn)協(xié)調(diào)問題瞬内。
這里我們將講解一下SDL的多線程與鎖機(jī)制迷雪。
引進(jìn)的機(jī)制:線程的互斥與同步
- 互斥:同一個(gè)資源在一定時(shí)間內(nèi)只能由一個(gè)方法訪問。
- 同步:一個(gè)方法完成后的內(nèi)容需要同步到其他的方法虫蝶,在由其他方法操作完成后的內(nèi)容章咧。
- 鎖與信號(hào)量
- 鎖用于完成互斥;信號(hào)量用于同步能真。
- 鎖的種類:讀寫鎖赁严、自旋鎖、可重入鎖粉铐。
SDL線程創(chuàng)建:SDL_CreateThread
SDL線程等待:SDL_WaitThead
SDL互斥鎖:SDL_CreateMutex / SDL_DestroyMutex
SDL鎖定互斥:SDL_LockMutex / SDL_UnlockMutex
SDL 條件變量(信號(hào)量):SDL_CreateCond / SDL_DestoryCond
SDL 條件變量(信號(hào)量)等待 / 通知 :SDL_CondWait / SDL_CondSingal
二疼约、代碼實(shí)現(xiàn):
我們通過SDL的鎖機(jī)制實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者
2.1、聲明
//mainwindow.h
Ui::MainWindow *ui;
/** 互斥鎖*/
SDL_mutex *_mutex = nullptr;
/** 條件變量:消費(fèi)者等待蝙泼,生產(chǎn)者喚醒 */
SDL_cond *_cond = nullptr;
std::list<QString> *_list = nullptr;
int _index = 0;
void consume(QString name);
void produce(QString name);
2.2程剥、創(chuàng)建鎖、消費(fèi)者
//mainwindow.cpp
// 創(chuàng)建互斥鎖
_mutex = SDL_CreateMutex();
// 創(chuàng)建條件變量
_cond = SDL_CreateCond();
// 創(chuàng)建鏈表
_list = new std::list<QString>();
// 創(chuàng)建消費(fèi)者
consume("消費(fèi)者1");
consume("消費(fèi)者2");
consume("消費(fèi)者3");
consume("消費(fèi)者4");
2.3汤踏、銷毀
MainWindow::~MainWindow(){
delete ui;
delete _list;
SDL_DestroyMutex(_mutex);
SDL_DestroyCond(_cond);
}
2.4织鲸、實(shí)現(xiàn)生產(chǎn)者邏輯
void MainWindow::produce(QString name){
std::thread([this,name](){
SDL_LockMutex(_mutex);
qDebug() << name << "開始生產(chǎn)";
_list->push_back(QString("%1").arg(++_index));
_list->push_back(QString("%1").arg(++_index));
_list->push_back(QString("%1").arg(++_index));
// 喚醒消費(fèi)者:趕緊開始消費(fèi)
SDL_CondSignal(_cond);
SDL_UnlockMutex(_mutex);
}).detach();
}
2.5、實(shí)現(xiàn)銷毀者邏輯
void MainWindow::consume(QString name){
std::thread([this,name](){
SDL_LockMutex(_mutex);
while (true) {
qDebug() << name << "開始消費(fèi)";
while (!_list->empty()) {
qDebug() << _list->front();
// 刪除頭部
_list->pop_front();
// 睡眠500ms
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
/**
* 1.釋放互斥鎖
* 2.等待條件_cond
* 3.等到了條件_cond茎活、加鎖
*/
SDL_CondWait(_cond,_mutex);
}
SDL_UnlockMutex(_mutex);
}).detach();
}
2.6昙沦、創(chuàng)建生產(chǎn)者
void MainWindow::on_produceBtn_clicked(){
// 創(chuàng)建生產(chǎn)者
produce("生產(chǎn)者1");
produce("生產(chǎn)者2");
produce("生產(chǎn)者3");
}
三、分裝SDL鎖機(jī)制
我們可以將SDL的鎖機(jī)制的api進(jìn)行二度分裝载荔,以便后面的音視頻使用
condmutex.h
#ifndef CONDMUTEX_H
#define CONDMUTEX_H
#include <SDL2/SDL.h>
class CondMutex {
public:
CondMutex();
~CondMutex();
void lock();
void unlock();
void signal();
void broadcast();
void wait();
private:
/** 互斥鎖 */
SDL_mutex *_mutex = nullptr;
/** 條件變量 */
SDL_cond *_cond = nullptr;
};
#endif // CONDMUTEX_H
condmutex.cpp
#include "condmutex.h"
CondMutex::CondMutex(){
// 創(chuàng)建互斥鎖
_mutex = SDL_CreateMutex();
// 創(chuàng)建條件變量
_cond = SDL_CreateCond();
}
CondMutex::~CondMutex(){
SDL_DestroyMutex(_mutex);
SDL_DestroyCond(_cond);
}
void CondMutex::lock(){
SDL_LockMutex(_mutex);
}
void CondMutex::unlock(){
SDL_UnlockMutex(_mutex);
}
void CondMutex::signal(){
SDL_CondSignal(_cond);
}
void CondMutex::broadcast(){
SDL_CondBroadcast(_cond);
}
void CondMutex::wait(){
SDL_CondWait(_cond,_mutex);
}