例一、生产者-消费者
一个任务制作烤面包(生产者),一个任务给烤面包抹黄油(消费者),还有一个任务是往抹好黄油的烤面包上抹果酱(消费者)。
代码如下:
#include "stdafx.h" #include "zthread/FastMutex.h" #include "zthread/CountedPtr.h" #include "zthread/Runnable.h" #include "zthread/Condition.h" #include <iostream> using namespace ZThread; using namespace std; class Jammer : public Runnable { public: Jammer() : butteredToastReady(Lock), jammed(0), isGotButteredToast(false){} void moreButteredToastReady() { Guard<Mutex> g(Lock); isGotButteredToast = true; butteredToastReady.signal(); } void run() { try { while (!Thread::interrupted()) { { Guard<Mutex> g(Lock); while (isGotButteredToast == false) butteredToastReady.wait(); ++jammed; } cout << "Putting jam on toast : " <<jammed <<endl; { Guard<Mutex> g(Lock); isGotButteredToast = false; } } } catch (Interrupted_Exception& e) { cout << " Jarry : "<< e.what() <<endl; } } private: Mutex Lock; Condition butteredToastReady; bool isGotButteredToast; int jammed; }; class Butterer : public Runnable { public: Butterer(CountedPtr<Jammer>& j) : toastReady(Lock), jammer(j), Buttered(0), isGotToast(false){} void moreToastReady() { Guard<Mutex> g(Lock); isGotToast = true; toastReady.signal(); } void run() { try { while (!Thread::interrupted()) { { Guard<Mutex> g(Lock); while (!isGotToast) toastReady.wait(); ++Buttered; } cout << "Buttering toast :" << Buttered <<endl; jammer->moreButteredToastReady(); { Guard<Mutex> g(Lock); isGotToast = false; } } } catch (Interrupted_Exception& e) { cout << " Jarry " << e.what() << endl; } } private: Mutex Lock; Condition toastReady; CountedPtr<Jammer> jammer; bool isGotToast; int Buttered; }; class Toast : public Runnable { public: Toast(CountedPtr<Butterer>& aButterer) : butterer(aButterer), toasted(0) {} void run() { try { while (!Thread::interrupted()) { Thread::sleep(1000); cout << "A new Toast" << ++toasted <<endl; butterer->moreToastReady(); } } catch (Interrupted_Exception& e) { cerr << "Jarry " << e.what() <<endl; } } private: CountedPtr<Butterer> butterer; int toasted; }; int _tmain(int argc, _TCHAR* argv[]) { try { CountedPtr<Jammer> jammer(new Jammer); CountedPtr<Butterer> butterer(new Butterer(jammer)); CountedPtr<Toast> toast(new Toast(butterer)); ThreadedExecutor executor; executor.execute(toast); executor.execute(jammer); executor.execute(butterer); cin.get(); executor.interrupt(); } catch (Synchronization_Exception& e) { cerr <<" Jarry Main " << e.what() <<endl; } return 0; }
线程处理问题常常基于需要对任务进行串行化处理。使用队列可以采用同步的方式访问其内部元素,这样可以解决很多线程处理问题,下面基于STL中的deque实现的队列:
#ifndef QUEUE_H #define QUEUE_H #include "zthread/Runnable.h" #include "zthread/PoolExecutor.h" template<class T> class TQueue { //锁子 ZThread::Mutex lock; //线程协作基类 ZThread::Condition cond; //线程队列元素 std::deque<T> data; public: TQueue() : cond(lock) {} void put(T item) { ZThread::Guard<ZThread::Mutex> g(lock); data.push_back(item); cond.signal(); } T get() { ZThread::Guard<ZThread::Mutex> g(lock); while(data.empty()) cond.wait(); T returnVal = data.front(); data.pop_front(); return returnVal; } }; #endif
1、加入同步以确保在同一时刻不会有两个线程添加对象。
2、加入wait()和signal()在队列空时,挂起线程,并在有多个元素可用时恢复执行。
二、广播
signal()函数唤醒了一个正在等待Condition对象的线程。然而,也许会有多个线程在等待某个相同的条件对象,在这种情况下需要使用broadcast()(与调用线程的个数的signal()效果相同)而不是signal()把这些线程唤醒。
使用广播的例子:每辆Car将在几个阶段内装配完成,本例中将看到这样一个阶段:底盘制作好之后的这段时间里可以 同时 安装发动机、驱动传动装置和车轮(广播)。本例中综合中前面中所有关于线程的知识。
#include <iostream> #include <string> #include "zthread/Thread.h" #include "zthread/Mutex.h" #include "zthread/Guard.h" #include "zthread/Condition.h" #include "zthread/ThreadedExecutor.h" #include "TQueue.h" using namespace ZThread; using namespace std; //driveTrain 驱动传动 class Car { int id; bool engine, driveTrain, wheels; public: Car(int idn) : id(idn), engine(false), driveTrain(false), wheels(false) {} // Empty Car object: Car() : id(-1), engine(false), driveTrain(false), wheels(false) {} // Unsynchronized -- assumes atomic bool operations: int getId() { return id; } void addEngine() { engine = true; } bool engineInstalled() { return engine; } void addDriveTrain() { driveTrain = true; } bool driveTrainInstalled() { return driveTrain; } void addWheels() { wheels = true; } bool wheelsInstalled() { return wheels; } friend ostream& operator<<(ostream& os, const Car& c) { return os << "Car " << c.id << " [" << " engine: " << c.engine << " driveTrain: " << c.driveTrain << " wheels: " << c.wheels << " ]"; } }; typedef CountedPtr< TQueue<Car> > CarQueue; class ChassisBuilder : public Runnable { CarQueue carQueue; int counter; public: ChassisBuilder(CarQueue& cq) : carQueue(cq),counter(0) {} void run() { try { while(!Thread::interrupted()) { Thread::sleep(100); // Make chassis: Car c(counter++); cout << c << endl; // Insert into queue carQueue->put(c); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "ChassisBuilder off" << endl; } }; class Cradle { Car c; // Holds current car being worked on bool occupied; Mutex workLock, readyLock; Condition workCondition, readyCondition; bool engineBotHired, wheelBotHired, driveTrainBotHired; public: Cradle() : workCondition(workLock), readyCondition(readyLock) { occupied = false; engineBotHired = true; wheelBotHired = true; driveTrainBotHired = true; } //向底盘生产线中加入car对象 //并修改底盘生产线的状态(被占用) void insertCar(Car chassis) { c = chassis; occupied = true; } //从底盘生产线中取出对象 //修正状态为未被占用,并返回car对象 Car getCar() { // Can only extract car once if(!occupied) { cerr << "No Car in Cradle for getCar()" << endl; return Car(); // "Null" Car object } occupied = false; return c; } // Access car while in cradle: //重载指向成员符号 //可以使用(*Cradle)直接调用 Car* operator->() { return &c; } // Allow robots to offer services to this cradle: void offerEngineBotServices() { Guard<Mutex> g(workLock); while(engineBotHired) workCondition.wait(); engineBotHired = true; // Accept the job } void offerWheelBotServices() { Guard<Mutex> g(workLock); while(wheelBotHired) workCondition.wait(); //这个wait被挂起,直到收到了startWork()的广播 //在startWork()中,雇佣的状态会被修改,因此下一步的操作是修正状态 wheelBotHired = true; // Accept the job } void offerDriveTrainBotServices() { Guard<Mutex> g(workLock); while(driveTrainBotHired) workCondition.wait(); driveTrainBotHired = true; // Accept the job } // Tell waiting robots that work is ready: void startWork() { Guard<Mutex> g(workLock); engineBotHired = false; wheelBotHired = false; driveTrainBotHired = false; workCondition.broadcast(); //等价于3个signal() //workCondition.signal(); //workCondition.signal(); //workCondition.signal(); } // Each robot reports when their job is done: void taskFinished() { Guard<Mutex> g(readyLock); //Guard<Mutex> g(workLock); readyCondition.signal(); } // Director waits until all jobs are done: void waitUntilWorkFinished() { Guard<Mutex> g(readyLock); while(!(c.engineInstalled() && c.driveTrainInstalled() && c.wheelsInstalled())) readyCondition.wait(); } }; typedef CountedPtr<Cradle> CradlePtr; class Director : public Runnable { CarQueue chassisQueue, finishingQueue; CradlePtr cradle; public: Director(CarQueue& cq, CarQueue& fq, CradlePtr cr) : chassisQueue(cq), finishingQueue(fq), cradle(cr) {} void run() { try { while(!Thread::interrupted()) { // Blocks until chassis is available: cradle->insertCar(chassisQueue->get()); // Notify robots car is ready for work cradle->startWork(); // Wait until work completes cradle->waitUntilWorkFinished(); // Put car into queue for further work finishingQueue->put(cradle->getCar()); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Director off" << endl; } }; class EngineRobot : public Runnable { CradlePtr cradle; public: EngineRobot(CradlePtr cr) : cradle(cr) {} void run() { try { while(!Thread::interrupted()) { // Blocks until job is offered/accepted: cradle->offerEngineBotServices(); cout << "Installing engine" << endl; (*cradle)->addEngine(); //隐式的调用了operator->()还是隐式的类型转换? cradle->taskFinished(); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "EngineRobot off" << endl; } }; class DriveTrainRobot : public Runnable { CradlePtr cradle; public: DriveTrainRobot(CradlePtr cr) : cradle(cr) {} void run() { try { while(!Thread::interrupted()) { // Blocks until job is offered/accepted: cradle->offerDriveTrainBotServices(); cout << "Installing DriveTrain" << endl; (*cradle.operator ->())->addDriveTrain(); cradle->taskFinished(); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "DriveTrainRobot off" << endl; } }; class WheelRobot : public Runnable { CradlePtr cradle; public: WheelRobot(CradlePtr cr) : cradle(cr) {} void run() { try { while(!Thread::interrupted()) { // Blocks until job is offered/accepted: cradle->offerWheelBotServices(); cout << "Installing Wheels" << endl; (*cradle)->addWheels(); cradle->taskFinished(); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "WheelRobot off" << endl; } }; class Reporter : public Runnable { CarQueue carQueue; public: Reporter(CarQueue& cq) : carQueue(cq) {} void run() { try { while(!Thread::interrupted()) { cout << carQueue->get() << endl; } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Reporter off" << endl; } }; int main() { cout << "Press <Enter> to quit" << endl; try { CarQueue chassisQueue(new TQueue<Car>), finishingQueue(new TQueue<Car>); CradlePtr cradle(new Cradle); ThreadedExecutor assemblyLine; assemblyLine.execute(new EngineRobot(cradle)); assemblyLine.execute(new DriveTrainRobot(cradle)); assemblyLine.execute(new WheelRobot(cradle)); assemblyLine.execute(new Director(chassisQueue, finishingQueue, cradle)); assemblyLine.execute(new Reporter(finishingQueue)); // Start everything running by producing chassis: assemblyLine.execute(new ChassisBuilder(chassisQueue)); cin.get(); assemblyLine.interrupt(); } catch(Synchronization_Exception& e) { cerr << e.what() << endl; } } ///:~