在C11中採用了thread創建多線程,以前的AfxBeginThread()這種方式不進行使用。
首先,使用線程函數需要添加頭文件#include <thread>
因爲使用以下使用的是多線程方式,所以也需要使用互斥操作#include <mutex>
第一步:線程的創建,在類中實現創建
std::thread pThread = std::thread(ThreadDataOperation, this);
當前顯示的是無參數的線程函數的調用,使用了線程創建之後,必須要明確 join() ? detach() 的方式,如果不寫,會在當前位置顯示異常。在這裏我用到的方式是detach()
pThread.detach();
在此,使用detach()時,有一個特別嚴重的問題,就是:主線程與當前創建的線程分離,如果創建的線程中存在指針時,主程序結束,指針則變成了非法指針,引起崩潰。
此時,需要用加鎖以及變量控制的方式來規避這個問題。
使用變量控制的方式,大家應該都不會陌生,舉一個簡單的例子
//以下是線程函數內部
{
while(true)
{
if(bStop == true)
{
break;
}
/*
線程中的具體操作流程
*/
}
bEnd = true; //走到了線程的最後一步
}
當滿足指定條件時,退出線程,時線程自動結束
在線程中使用加鎖的方式,方式detach()出現野指針現象
下面使用一種比較笨的方式來停止線程。
bStop = true;//停止當前正在運行的線程
while(true)
{
if(bEnd == true)
{
TRACE("當前線程已經停止運行\n");//輸出log
}
else
{
Sleep(100); //線程未停止
}
}
在這裏,我用了一個bEnd的變量來判斷是否運行到了線程的最後一步,確保線程函數運行完成。
如果不想用這種比較笨的方式,下面我們可以用加鎖的方式來控制detach()的線程是否正常結束
有人會問,爲什麼要在線程調用函數中加鎖?當使用detach()方式時,想要外界控制停止線程的運行時,單靠一個變量是無法準確的表達主線程結束時,確保detach()的線程要先結束。
{
dataMutex.lock();
/*
線程中數據處理主要邏輯
*/
dataMutex.unlock();
}
當外界停止線程的時候的操作
bStop = true; //停止當前正在運行的線程
dataMutex.lock();
dataMutex.unlock();
怎麼又要在停止的時候加鎖呢?
因爲在線程中有一個加鎖機制,當又來一個鎖機制時,此時需要等待上一個鎖執行完成之後纔會執行後一個鎖機制,屬於排隊執行。可以實現while循環的等待功能。
下面是多線程類核心代碼
.h文件
#pragma once
#include <string>
#include <map>
#include <thread> //C++11 開線程
#include <mutex> //C++11 互斥
//當前結構用來記錄每一條線程數據內容
typedef struct OperationData
{
bool bStartThread; //是否開始線程?
bool bEndPush; //是否停止此次線程的操作
std::thread *pThread; //對應線程指針
std::mutex dataMutex; //互斥加鎖機制
/*
當前結構只是存儲表達多線程操作,不存在數據交互
如果想要實現真實數據操作,只需在此自行添加即可。
*/
OperationData():bStartThread(false), pThread(nullptr), bEndPush(false) {}
}s_threadData;
class COperationThread
{
public:
COperationThread();
~COperationThread();
/*
真實數據操作接口
*/
/*************************************************
Function: StartVideoStream
Description: 開啓線程
Parma:
nThreadIndex:需要開啓的線程編號
Return: void
*************************************************/
void StartThread(int nThreadIndex);
/*************************************************
Function: StopThread
Description: 停止指定的線程
Parma:
nThreadIndex:需要停止的線程編號
Return: void
*************************************************/
void StopThread(int nThreadIndex);
protected:
//開啓線程的函數
UINT ThreadOperationData(s_threadData* stInfo);
private:
std::map<int, s_threadData*> m_mapThreadData; //存儲多線程數據
};
.cpp實現操作文件
#include "pch.h"
#include "TestDemo.h"
COperationThread::COperationThread()
{
}
COperationThread::~COperationThread()
{
//此時,需要將map容器中的數據釋放
std::map<int, s_threadData*>::iterator itmap = m_mapThreadData.begin();
for (itmap ; itmap!= m_mapThreadData.end() ; itmap++)
{
if (itmap->second->bEndPush == false)
{
//TODO:線程還未停止,需要等待停止
itmap->second->bStartThread = false;
itmap->second->dataMutex.lock();
itmap->second->dataMutex.unlock();
//線程結束之後,銷燬new出來的地址
delete itmap->second;
itmap->second = nullptr;
}
else
{
//TODO:線程已經關閉,直接銷燬即可
delete itmap->second;
itmap->second = nullptr;
}
}
m_mapThreadData.clear(); //清空容器,保證不存在任何泄漏
}
void COperationThread::StartThread(int nThreadIndex)
{
//TODO:判斷存儲多線程的容器中是否存在當前要打開的編號數據?
std::map<int, s_threadData*>::iterator itFind = m_mapThreadData.find(nThreadIndex);
if (itFind == m_mapThreadData.end())
{
//TODO:容器中沒有存在次編號的數據,需要進行存儲,且開啓一個新線程
s_threadData* stInfo = new s_threadData(); //必須!!!
//數據賦值
stInfo->bEndPush = false; //當前線程操作未結束
stInfo->bStartThread = true; //需要開啓新的線程
std::thread pThread = std::thread(&COperationThread::ThreadOperationData , this , stInfo);
stInfo->pThread = &pThread;
pThread.detach();
m_mapThreadData.insert(std::make_pair(nThreadIndex, stInfo));
}
else
{
//TODO:已經存在當前編號的數據了,需要停止上一次的線程操作
//這一步是整個類的核心關鍵
if (itFind->second->bEndPush == false)
{
//TODO:線程還未正常退出時,停止當前的線程
itFind->second->bStartThread = false;//變量控制停止
itFind->second->dataMutex.lock(); //加鎖
itFind->second->dataMutex.unlock(); //解鎖
}
else
{
//TODO:線程已經停止,重新開啓一個線程
itFind->second->bEndPush = false;
itFind->second->bStartThread = true;
std::thread pThread = std::thread(&COperationThread::ThreadOperationData, this, itFind->second);
itFind->second->pThread = &pThread;
pThread.detach();
}
}
}
void COperationThread::StopThread(int nThreadIndex)
{
//TODO:查詢指定編號的線程,進行停止
std::map<int, s_threadData*>::iterator itFind = m_mapThreadData.find(nThreadIndex);
if (itFind == m_mapThreadData.end())
{
//TODO:未找到對應編號的線程,自行處理
}
else
{
if (itFind->second->bEndPush == true)
{
//TODO:當前線程已經停止,無需再次停止,自行處理
}
else
{
//TODO:停止指定線程
itFind->second->bStartThread = false;
itFind->second->dataMutex.lock();
itFind->second->dataMutex.unlock();
}
}
}
UINT COperationThread::ThreadOperationData(s_threadData * stInfo)
{
stInfo->dataMutex.lock();
//簡單例子說明
while (true)
{
if (stInfo->bStartThread == false)
{
break;
}
/*
具體的線程數據操作
*/
}
stInfo->bEndPush = true; //線程運行到最後
stInfo->dataMutex.unlock();
return 0;
}
以上就是在類中實現多線程操作的例子。只是寫了線程的應用,對於數據的處理,可以根據需求更外添加。
以上就是我對C11多線程的理解,如果有疑問可以留言。