在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多线程的理解,如果有疑问可以留言。