C++实现一个多线程同步方式的协同工作程序示例
多线程并发程序与协同程序其实是不同的概念。多线程并发是多个执行序同时运行,而协同程序是多个执行序列相互协作,同一时刻只有一个执行序列。今天想到的是将两者结合起来,拿现实生活中的例子来说,假设一个班级有100个学生,一个老师要批改100个学生的作业,有时老师太忙或者赶时间会叫几个同学帮忙批改,等所有同学都批改完后都交到老师手中,老师在下次上课的时候将作业本一起发给班上的学生。。。。其实在并发编程的时候也可以借鉴这一个思想和模式,特别是网络服务器开发的过程中,并发与协同经常出现,于是今天写了一个简单的程序模拟了这种情形,当然这个程序本身并没有任何意义,只是记录下这种思想,个人一直都觉得,程序开发中,思想是最为重要的,用什么语言来实现只是表现上不同,今天记录下来,日后的开发过程中,在适当地方以此思想为基础,根据项目需要进行拓展!
//--------------------------------------------------------------
开发工具:Visual Studio
//---------------------------------------------------------------
//C++
#include <iostream>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector> using namespace std; //windows
#include <windows.h> /************************************************
[示例]实现一个多线程方式下的协同工作程序 当一个线程(相对的主线程)在完成一个任务的时
候,有时候为了提高效率,可以充分利用多核CPU的
优势可以将手中的任务分成多个部分,分发给比较
空闲的辅助线程来帮助处理,并且主线程要等待所
有的辅助线程都处理完成后,对所有任务进行一次
汇总,才能进行下一步操作,此时就需要一个同步的
多线程协同工作类。
*************************************************/ //定义一个求累积和的任务类
class CSumTask
{
public:
CSumTask(double dStart,double dEnd);
~CSumTask();
double DoTask();
double GetResult();
private:
double m_dMin;
double m_dMax;
double m_dResult;
}; CSumTask::CSumTask(double dStart,double dEnd):m_dMin(dStart),m_dMax(dEnd),m_dResult(0.0)
{ }
CSumTask::~CSumTask()
{ }
double CSumTask::DoTask()
{ for(double dNum = m_dMin;dNum <= m_dMax;++dNum)
{
m_dResult += dNum;
}
return m_dResult;
} double CSumTask::GetResult()
{
return m_dResult;
} //定义一个任务管理者
class CTaskManager
{
public:
CTaskManager();
~CTaskManager();
size_t Size();
void AddTask(const std::shared_ptr<CSumTask> TaskPtr);
std::shared_ptr<CSumTask> PopTask();
protected:
std::queue<std::shared_ptr<CSumTask>> m_queTask;
}; CTaskManager::CTaskManager()
{ } CTaskManager::~CTaskManager()
{ } size_t CTaskManager::Size()
{
return m_queTask.size();
} void CTaskManager::AddTask(const std::shared_ptr<CSumTask> TaskPtr)
{
m_queTask.push(std::move(TaskPtr));
} std::shared_ptr<CSumTask> CTaskManager::PopTask()
{
std::shared_ptr<CSumTask> tmPtr = m_queTask.front();
m_queTask.pop();
return tmPtr;
} //协同工作线程管理类,负责创建协同工作线程并接受来自主线程委托的任务进行处理
class CWorkThreadManager
{
public:
CWorkThreadManager(unsigned int uiThreadSum );
~CWorkThreadManager();
bool AcceptTask(std::shared_ptr<CSumTask> TaskPtr);
bool StopAll(bool bStop);
unsigned int ThreadNum();
protected:
std::queue<std::shared_ptr<CSumTask>> m_queTask;
std::mutex m_muTask;
int m_iWorkingThread;
int m_iWorkThreadSum;
std::vector<std::shared_ptr<std::thread>> m_vecWorkers; void WorkThread(int iWorkerID);
bool m_bStop;
std::condition_variable_any m_condPop;
std::condition_variable_any m_stopVar;
}; CWorkThreadManager::~CWorkThreadManager()
{ }
unsigned int CWorkThreadManager::ThreadNum()
{
return m_iWorkThreadSum;
} CWorkThreadManager::CWorkThreadManager(unsigned int uiThreadSum ):m_bStop(false),m_iWorkingThread(),m_iWorkThreadSum(uiThreadSum)
{
//创建工作线程
for(int i = ; i < m_iWorkThreadSum;++i)
{
std::shared_ptr<std::thread> WorkPtr(new std::thread(&CWorkThreadManager::WorkThread,this,i+));
m_vecWorkers.push_back(WorkPtr);
} } bool CWorkThreadManager::AcceptTask(std::shared_ptr<CSumTask> TaskPtr)
{
std::unique_lock<std::mutex> muLock(m_muTask);
if(m_iWorkingThread >= m_iWorkThreadSum)
{
return false; //当前已没有多余的空闲的线程处理任务
}
m_queTask.push(TaskPtr);
m_condPop.notify_all();
return true;
} void CWorkThreadManager::WorkThread(int iWorkerID)
{
while(!m_bStop)
{
std::shared_ptr<CSumTask> TaskPtr;
bool bDoTask = false;
{
std::unique_lock<std::mutex> muLock(m_muTask);
while(m_queTask.empty() && !m_bStop)
{
m_condPop.wait(m_muTask);
}
if(!m_queTask.empty())
{
TaskPtr = m_queTask.front();
m_queTask.pop();
m_iWorkingThread++;
bDoTask = true;
} }
//处理任务
if(bDoTask)
{
TaskPtr->DoTask();
{
std::unique_lock<std::mutex> muLock(m_muTask);
m_iWorkingThread--;
cout<<">>>DoTask in thread ["<<iWorkerID<<"]\n";
}
}
m_stopVar.notify_all();
}
} bool CWorkThreadManager::StopAll(bool bStop)
{
{
std::unique_lock<std::mutex> muLock(m_muTask);
while(m_queTask.size()> || m_iWorkingThread>)
{
m_stopVar.wait(m_muTask);
cout<<">>>Waiting finish....\n";
}
cout<<">>>All task finished!\n"; } m_bStop = true;
m_condPop.notify_all();
//等待所有线程关闭
for(std::vector<std::shared_ptr<std::thread>>::iterator itTask = m_vecWorkers.begin();itTask != m_vecWorkers.end();++itTask)
{
(*itTask)->join();
}
return true;
} /**************************************
[示例程序说明] 每个任务对象表示求1+2+....+1000的累
积和,现在有2000个这样的任务,需要将每个
任务进行计算,然后将所有的结果汇总求和。
利用多线程协同工作类对象辅助完成每
个任务结果计算,主线程等待所有结果完成
后将所有结果汇总求和。
****************************************/ int main(int arg,char *arv[])
{ std::cout.sync_with_stdio(true);
CTaskManager TaskMgr;
CWorkThreadManager WorkerMgr();
std::vector<std::shared_ptr<CSumTask>> vecResultTask; for(int i = ; i < ; ++i)
{
std::shared_ptr<CSumTask> TaskPtr(new CSumTask(1.0,1000.0));
TaskMgr.AddTask(TaskPtr);
vecResultTask.push_back(TaskPtr);
} //
DWORD dStartTime = ::GetTickCount();
while(TaskMgr.Size()>)
{
std::shared_ptr<CSumTask> WorkPtr = TaskMgr.PopTask();
if(!WorkerMgr.AcceptTask(WorkPtr))
{
//辅助线程此刻处于忙碌状态(没有空闲帮忙),自己处理该任务
WorkPtr->DoTask();
cout<<">>>DoTask in thread [0]\n";
}
}
WorkerMgr.StopAll(true); //等待所有的任务完成 //对所有结果求和
double dSumResult = 0.0;
for(std::vector<std::shared_ptr<CSumTask>>::iterator itTask = vecResultTask.begin();itTask != vecResultTask.end();++itTask)
{
dSumResult += (*itTask)->GetResult();
} DWORD dEndTime = ::GetTickCount();
cout<<"\n[Status]"<<endl;
cout<<"\tEvery task result:"<<vecResultTask[]->GetResult()<<endl;
cout<<"\tTask num:"<<vecResultTask.size()<<endl;
cout<<"\tAll result sum:"<<dSumResult;
cout<<"\tCast to int,result:"<<static_cast<long long>(dSumResult)<<endl;
cout<<"\tWorkthread num:"<<WorkerMgr.ThreadNum()<<endl;
cout<<"\tTime of used:"<<dEndTime-dStartTime<<" ms"<<endl;
getchar();
return ;
}
C++实现一个多线程同步方式的协同工作程序示例的更多相关文章
- Linux多线程同步方式
当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,就可能出现偏差,得到与预期不符合的值.为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下:而操作 ...
- Java中多线程同步类 CountDownLatch
在多线程开发中,常常遇到希望一组线程完成之后在执行之后的操作,java提供了一个多线程同步辅助类,可以完成此类需求: 类中常见的方法: 其中构造方法:CountDownLatch(int count) ...
- Java中使用CountDownLatch进行多线程同步
CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...
- 多线程编程之Windows同步方式
在Windows环境下针对多线程同步与互斥操作的支持,主要包括四种方式:临界区(CriticalSection).互斥对象(Mutex).信号量(Semaphore).事件对象(Event).下面分别 ...
- Java多线程同步问题:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.一个简单的Demo引发的血案 关于线程同步问题我们从一个 ...
- JAVA\Android 多线程实现方式及并发与同步
转载:https://blog.csdn.net/csdn_aiyang/article/details/65442540 概述 说到线程,就不得不先说线程和进程的关系,这里先简单解释一下,进 ...
- 试着用c写了一个多线程的同步
在Java中写多线程相关的程序简单很多,在多线程中需要同步的时候,使用synchronized就行了. 最近学习c的多线程与同步,感觉实现起来,要写的代码比较多一些,这也许是因为java封装的比较好吧 ...
- [一个经典的多线程同步问题]解决方案二:Event事件
使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件E ...
- [一个经典的多线程同步问题]解决方案一:关键段CS
前面提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文先介绍如何使用关键段,然后再深层次的分析下关键段的实现机制和原理. 关键段CRITICA ...
随机推荐
- SQLite 在Windows Server 2008 R2 部署问题FAQ汇总[轉]
轉自:http://www.steveluo.name/sqlite-windows-server-2008-r2-deploy-faq/ 今天花了一天的时间研究了一下SQLite,以取代一些轻量级项 ...
- 组件局域网中的无集线器、Windows XP、Windows 7、Windows 8的对等网
为什么要用对等网? 答:对等网采用分散管理的方式,网络中的每台计算机既作为客户机又可作为服务器来工作,每个用户都管理自己机器上的资源. 组建局域网中无集线器的对等网 组建局域网中Windows XP ...
- 校友信息管理系统&SNS互动平台之用户需求及概要设计
前言.提纲及说明: 请移步:<校友信息管理&SNS互动平台之前言.目录及说明>(博客园地址:http://www.cnblogs.com/s6cn/p/3516876.html) ...
- Ⅷ.spring的点点滴滴--抽象对象和子对象
承接上文 抽象对象和子对象 .net篇(环境为vs2012+Spring.Core.dll v1.31) public class parent { public string Name { get; ...
- 使用VisualSVN Server搭建SVN服务器(转载)
转载于http://www.cnblogs.com/greywolf/archive/2013/01/28/2879952.html 使用 VisualSVN Server来实现主要的 SVN功能则要 ...
- 【Servlet】Filter过滤器的编写和配置
Servlet的Filter介绍 在Servlet作为过滤器使用时,它可以对客户的请求进行过滤处理,当它处理完成后,它会交给下一个过滤器处理,就这样,客户的请求在过滤链里一个个处理,直到请求发送到目标 ...
- cocos2dx lua学习笔记 <一> quick 3.5定义本身C++类是必然lua
请尊重原创 转载有名源:http://blog.csdn.net/wushao126/article/details/46660375 首先去官网下载最新的quick.配置好环境.创建一个luapro ...
- “DBUtility.DbHelperSQL”的类型初始值设定项引发异常 “DBUtility.DbHelperSQL”的类型初始值设定项引发异常
今天遇到了一个这样的问题“DBUtility.DbHelperSQL”的类型初始值设定项引发异常“DBUtility.DbHelperSQL”的类型初始值设定项引发异常 也许有和我遇到这问题的人也在这 ...
- Oracle 流式制造功能培训
转自百度文库: http://wenku.baidu.com/link?url=dRyll_P7C3fepoUp5dggYVzw6lVmifwEJMLvis1CN58m09WYF1unY3Ddn9Lq ...
- ReadWriteLock与ReentrantReadWriteLock
JAVA的JUC包中的锁包括"独占锁"和"共享锁".JUC中的共享锁有:CountDownLatch.CyclicBarrier.Semaphore.Reent ...