多线程并发程序与协同程序其实是不同的概念。多线程并发是多个执行序同时运行,而协同程序是多个执行序列相互协作,同一时刻只有一个执行序列。今天想到的是将两者结合起来,拿现实生活中的例子来说,假设一个班级有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++实现一个多线程同步方式的协同工作程序示例的更多相关文章

  1. Linux多线程同步方式

    当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图,当多个线程同时去修改这片内存时,就可能出现偏差,得到与预期不符合的值.为啥需要同步,一件事情逻辑上一定是有序的,即使在并发环境下:而操作 ...

  2. Java中多线程同步类 CountDownLatch

    在多线程开发中,常常遇到希望一组线程完成之后在执行之后的操作,java提供了一个多线程同步辅助类,可以完成此类需求: 类中常见的方法: 其中构造方法:CountDownLatch(int count) ...

  3. Java中使用CountDownLatch进行多线程同步

    CountDownLatch介绍 在前面的Java学习笔记中,总结了Java中进行多线程同步的几个方法: 1.synchronized关键字进行同步. 2.Lock锁接口及其实现类ReentrantL ...

  4. 多线程编程之Windows同步方式

    在Windows环境下针对多线程同步与互斥操作的支持,主要包括四种方式:临界区(CriticalSection).互斥对象(Mutex).信号量(Semaphore).事件对象(Event).下面分别 ...

  5. Java多线程同步问题:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.一个简单的Demo引发的血案 关于线程同步问题我们从一个 ...

  6. JAVA\Android 多线程实现方式及并发与同步

    转载:https://blog.csdn.net/csdn_aiyang/article/details/65442540 概述     说到线程,就不得不先说线程和进程的关系,这里先简单解释一下,进 ...

  7. 试着用c写了一个多线程的同步

    在Java中写多线程相关的程序简单很多,在多线程中需要同步的时候,使用synchronized就行了. 最近学习c的多线程与同步,感觉实现起来,要写的代码比较多一些,这也许是因为java封装的比较好吧 ...

  8. [一个经典的多线程同步问题]解决方案二:Event事件

    使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件E ...

  9. [一个经典的多线程同步问题]解决方案一:关键段CS

    前面提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文先介绍如何使用关键段,然后再深层次的分析下关键段的实现机制和原理. 关键段CRITICA ...

随机推荐

  1. storm的功能、三大应用

    storm的功能 Storm 有许多应用领域:实时分析.在线机器学习.持续计算.分布式 RPC(远过程调用协议,一种通过网络从远程计算机程序上请求服务). ETL(Extraction-Transfo ...

  2. GPUImage的简单使用

    GPUImage 是一个开源的图像处理库,提供了非常多的滤镜效果来加工图片.GPUImage 并不像一般的第三方库可以直接拖入到工程中使用,而是需要先在本地编译,然后将编译后的文件拖入到工程中使用.配 ...

  3. cocos2d-x 屏幕适配新解

    转自:http://blog.leafsoar.com/archives/2013/05-10-19.html 为了适应移动终端的各种分辨率大小,各种屏幕宽高比,在 cocos2d-x(当前稳定版:2 ...

  4. MyEclipse高效开发之必备快捷键技能

    学习了Java之后,使用MyEclipse开发已经有一段时间了,奈何MyEclipse的界面是英文版的,很多功能都不了解,对于那些英文,每次在调程序的时候,都需要一个一个的查,效率很是低下.于是,就想 ...

  5. AIDL-Android接口描述语言实现跨进程通讯

    在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢? 显然, Java中不允许跨进程内存共享. 因此传递对象, ...

  6. [译]信仰是怎样毁掉程序猿的How religion destroys programmers

    作者原文地址 作者John Sonmez 英文水平不够高,翻译不太准确. 翻译地址:译文 尽管文章是13年的,可是这段时间恰好看到.net开源核心之后,各种java和.net掐架. 语言之争有些牵涉到 ...

  7. android106 C基本数据类型

    #JNI java native interface #c的基本数据类型 * int:32位,能表示的数字是2的32次方个 * 最高位用来表示符号位,那么还剩下31位可以表示数值,所以能表示的数字就是 ...

  8. How to Enable Multi-Touch

    This is a frequently asked question. Multi-touch feature is available on both iOS & Android port ...

  9. zTree下拉菜单多级菜单多选实现

    惯例,先上图: 这是在一个项目中,为了满足样式美观.多级菜单以及多选而将zTree插件更改过后的效果. 在实际的开发过程中,本来zTree也是可以满足需求的,但是zTree多选的话需要checkbox ...

  10. Git 安装与简单使用(新手必看)

    1.安装git,默认下一步下一步等待安装完成 2.设置全局账号 安装之后去快速启动栏点击GitBash git config --global user.name "xiefeng" ...