一、简介
为什么要用多线程?在音视频领域主要是实现音视频同步。实现了音视频同步,我们的播放器就基本上合格了。
多线程的好处主要是能使程序更加充分利用硬件(主要是CPU)的性能。但是也存在相应的隐患,如果多线程管理不好,会出现协调问题。
这里我们将讲解一下SDL的多线程与锁机制。
引进的机制:线程的互斥与同步
- 互斥:同一个资源在一定时间内只能由一个方法访问。
- 同步:一个方法完成后的内容需要同步到其他的方法,在由其他方法操作完成后的内容。
- 锁与信号量
- 锁用于完成互斥;信号量用于同步。
- 锁的种类:读写锁、自旋锁、可重入锁。
| SDL线程创建:SDL_CreateThread |
| |
| SDL线程等待:SDL_WaitThead |
| |
| SDL互斥锁:SDL_CreateMutex / SDL_DestroyMutex |
| |
| SDL锁定互斥:SDL_LockMutex / SDL_UnlockMutex |
| |
| SDL 条件变量(信号量):SDL_CreateCond / SDL_DestoryCond |
| |
| SDL 条件变量(信号量)等待 / 通知 :SDL_CondWait / SDL_CondSingal |
二、代码实现:
我们通过SDL的锁机制实现生产者和消费者
2.1、声明
| |
| |
| Ui::MainWindow *ui; |
| |
| SDL_mutex *_mutex = nullptr; |
| |
| SDL_cond *_cond = nullptr; |
| |
| std::list<QString> *_list = nullptr; |
| int _index = 0; |
| |
| void consume(QString name); |
| void produce(QString name); |
2.2、创建锁、消费者
| |
| |
| |
| _mutex = SDL_CreateMutex(); |
| |
| _cond = SDL_CreateCond(); |
| |
| |
| _list = new std::list<QString>(); |
| |
| |
| consume("消费者1"); |
| consume("消费者2"); |
| consume("消费者3"); |
| consume("消费者4"); |
2.3、销毁
| MainWindow::~MainWindow(){ |
| delete ui; |
| delete _list; |
| SDL_DestroyMutex(_mutex); |
| SDL_DestroyCond(_cond); |
| } |
2.4、实现生产者逻辑
| void MainWindow::produce(QString name){ |
| std::thread([this,name](){ |
| SDL_LockMutex(_mutex); |
| |
| qDebug() << name << "开始生产"; |
| |
| _list->push_back(QString("%1").arg(++_index)); |
| _list->push_back(QString("%1").arg(++_index)); |
| _list->push_back(QString("%1").arg(++_index)); |
| |
| |
| SDL_CondSignal(_cond); |
| |
| SDL_UnlockMutex(_mutex); |
| }).detach(); |
| } |
2.5、实现销毁者逻辑
| void MainWindow::consume(QString name){ |
| std::thread([this,name](){ |
| SDL_LockMutex(_mutex); |
| while (true) { |
| qDebug() << name << "开始消费"; |
| while (!_list->empty()) { |
| qDebug() << _list->front(); |
| |
| _list->pop_front(); |
| |
| std::this_thread::sleep_for(std::chrono::milliseconds(500)); |
| } |
| |
| |
| |
| |
| |
| SDL_CondWait(_cond,_mutex); |
| } |
| SDL_UnlockMutex(_mutex); |
| }).detach(); |
| } |
2.6、创建生产者
| void MainWindow::on_produceBtn_clicked(){ |
| |
| produce("生产者1"); |
| produce("生产者2"); |
| produce("生产者3"); |
| } |
三、分装SDL锁机制
我们可以将SDL的锁机制的api进行二度分装,以便后面的音视频使用
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.cpp
| #include "condmutex.h" |
| |
| CondMutex::CondMutex(){ |
| |
| _mutex = SDL_CreateMutex(); |
| |
| _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); |
| } |
| |
代码链接1
代码链接2
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库