IBM的ZThread库

下载地址

 

去除调试信息:

在Debug.h中的最前端增加#define ZTDEBUG(x),忽略警告,DONE

 

这个库用起来应该比Linux系统下提供的并发的借口要来的舒坦,不知道有没有TBB快速,但是可以肯定的是为程序员省掉了很多代码的编辑工作。

 

Mark一下,认真学习之。

 

 

当需要使用多线程库的时候,需要从Runnable共有继承产生一个类,然后重新定义run()函数

代码如下:

 

#include <iostream> #include "zthread/Runnable.h" #include "zthread/Thread.h" using namespace ZThread; class LiftOff:public ZThread::Runnable { public: LiftOff(int count,int ident = 0): countDown(count),id(ident){} ~LiftOff() { std::cout<<id<<"completed"<<std::endl; } void run()//run in the file Runnable is a virtual funciton! { while(countDown--) { std::cout<<id<<":"<<countDown<<std::endl; } std::cout<<"LiftOff!"<<std::endl; } private: int countDown; int id; }; int main() { //LiftOff launch(18); //launch.run(); try { for (int i = 0;i<10;++i) { Thread t (new LiftOff(10,i)); std::cout<<"waiting for LiftOff!"<<std::endl; } } catch(Synchronization_Exception &e) { std::cerr<<e.what()<<std::endl; } return 0; }

Code1-1

 

Synchronization_Exception是ZThread库的一部分,是该库处理异常的一个类,当出错时会抛出该类的对象

 

当创建了一个Thread对象的时候,相关联的线程就会在线程处理系统内注册,并保持活动状态。

 

以下是一个响应UI的例子:

#include <iostream> #include <fstream> #include <string> #include "zthread/Thread.h" using namespace std; using namespace ZThread; class DisplayTask:public Runnable { public: DisplayTask(const string &file):quitFlag(false) { in.open(file.c_str()); } ~DisplayTask(){in.close();} void run() { while (getline(in,line) &&quitFlag) { cout<<line<<endl; Thread::sleep(500); } } void quit(){quitFlag = true;} protected: private: ifstream in; string line; bool quitFlag; }; int main() { try { cout<<"press <Enter> to quit!"<<endl; DisplayTask *dt = new DisplayTask("C11-ResponsUI.cpp"); Thread t(dt); cin.get(); dt->quit(); } catch (Synchronization_Exception &e) { cerr<<e.what()<<endl; } cout<<"Shutting down..."<<endl; }

Code1-2

 

该例子也表明了任务之间需要通信。当药销毁一个任务时,有任务自己决定什么时候停止是最安全的——设置一个布尔标记,来通知任务停止。

 

使用执行器(Executor)简化工作

执行器在客户端和任务的执行之间提供了一个间接层,客户不再直接执行任务,而是由中间的对象来执行。

#include <iostream> #include "zthread/ThreadedExecutor.h" using namespace std; using namespace ZThread; class LiftOff:public ZThread::Runnable { public: LiftOff(int count,int ident = 0): countDown(count),id(ident){} ~LiftOff() { std::cout<<id<<"completed"<<std::endl; } void run()//run in the file Runnable is a virtual funciton! { while(countDown--) { std::cout<<id<<":"<<countDown<<std::endl; } std::cout<<"LiftOff!"<<std::endl; } private: int countDown; int id; }; int main() { try { ThreadedExecutor executor; for (int i=0;i<5;++i) { executor.execute(new LiftOff(10,i)); } } catch(Synchronization_Exception* e) { cerr<<e->what()<<endl; } return 0; }

Code1-3

 

 

对比Code1-3和Code1-1可以看出差别——1-3中不再需要一个Thread的对象了(意味着不再直接调用线程?),用一个中间对象ThreadExecutor代替之。

 

ThreadExecutor的缺陷:需要为每一个任务都创建线程,由于创建了过多线程会导致过多的开销。

                                   必须用try包裹,因为出错会抛出Synchronization_Exception的对象

 

在某些情况下可以用单个Executor对象来创建和管理所有的线程(什么情况?)

 

当ThreadExecutor开销过大的时候使用PoolExecutor来代替

 

使用有限的线程集用并行的方式提交任务:代码代码~~

 

#include <iostream> #include "zthread/PoolExecutor.h" using namespace std; using namespace ZThread; class LiftOff:public ZThread::Runnable { public: LiftOff(int count,int ident = 0): countDown(count),id(ident){} ~LiftOff() { std::cout<<id<<"completed"<<std::endl; } void run()//run in the file Runnable is a virtual funciton! { while(countDown--) { std::cout<<id<<":"<<countDown<<std::endl; } std::cout<<"LiftOff!"<<std::endl; } private: int countDown; int id; }; int main() { try { PoolExecutor executor(5);//指定线程池大小 for (int i=0;i<5;++i) { executor.execute(new LiftOff(10,i)); } } catch(Synchronization_Exception* e) { cerr<<e->what()<<endl; } return 0; } 

Code1-4

 

ConcurrentExecutor类和PoolExecutor类类似,该类只有一个线程,常用于长期处于活动状态的任务(例如监听套接字),

或者短任务,例如更新日志。当有多个任务提交给该对象时,所有的任务都是串行化执行。

 

和ConcurrentExecutor类似,SynchronizationExecutor用于需要同一时刻只运行一个任务的时候,串行代替了并发。

但是该类不会创建和管理线程,它只使用提交任务的线程,因此只会作为同步的焦点(?)

 

优先级的设置:

不能使用Executor的中间对象,必须使用Thread对象(需要通过线程来设定优先级)

优先级分为三级(High,Low,Medium)

 

保证对象的存在以及共享资源:

必须使用new来创建对象(使之存在于内存堆上),创建完成之后,不必显式的删除对象(任务会完成删除的工作),因为涉及

到引用计数的问题,该工作只能由其完成!!!

 

补充一点关于volatile的知识:

需要使用volatile的地方:
  1). 并行设备的硬件寄存器(如:状态寄存器)
    2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
      3). 多线程应用中被几个任务共享的变量
      一个参数既可以是volatile也可以是const
      指针可以是volatile类型
      优化和多线程之间的折中办法
     1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
     2、多任务环境下各任务间共享的标志应该加volatile;
     3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
    另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打断了重写),
    在1中可以通过关中断来实现,2中可以禁止任务调度,3中则只能依靠硬件的良好设计了。

 

抽象类一般都用于设定一个统一的接口,例如ZThread中的Runnable和Cancelable两个类,其中的函数均为纯虚函数。

 

依赖于Cancelable的对象的所有任务都要测试这个标志来检查该对象是否被取消。

 

访问控制的Mutex机制:

需要使用的两个函数,lock.acquire();lock.release();

死锁的产生--如果从临界区中返回,没有释放该锁,将阻止其再次从临界区获得该锁。

 

使用保护简化代码的工作量(因为如果单独使用Mutex对象,需要对每一个对象执行acquire和release操作),而Guard

模板的实现,大量的简化了这个的工作量;

只需要在加锁数据的时候使用Gurad<Mutex>gm(lock);

之后完全不用操心什么时候释放这个锁。

 

关于Guard:

1. Guard也可以用来临时解锁一个保护(Code1-5)

2. Guard可以尝试在某一个确定的时间获得某个锁,然后放弃(Code1-6)

   在这里要注意的就是如果在时间内不能获得锁,将会

 

#include "zthread/Thread.h" #include "zthread/Mutex.h" #include "zthread/Guard.h" using namespace ZThread; class TemporryUnlock { public: void f() { Guard<Mutex>g(lock); //next in some implication we need to unlock this lock { Guard<Mutex,UnlockedScope>h(g); } } protected: private: Mutex lock; }; int main() { TemporryUnlock t; t.f(); return 0; }

                                                                                     Code1-5

 

class TimedLock { public: void fun() { try { Guard<Mutex,TimedLockedScope<500> >g(lock); //... } catch (Timeout_Exception& e) { std::cerr<<e.what()<<std::endl; } } protected: private: Mutex lock; };

                                                                                      Code1-6

 

同步整个类:

使用模板GuardClass,这样能确保在任意时刻一个类对象只有一个===函数===在运行

 

关于线程安全性:

代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。摘自百度百科

 

另外,在头文件threadlock中源代码需要做一个略微的修正:

        const Value& operator=(const T& v) { value = v; return *this;}//modified by HIT
        const Value& operator=(const T& v) { value = v; }

否则会报没有返回值的错误

 

原子操作:

在一个微处理器指令中完成并且不能够被中断,例如返回一个int值或者++num的操作,多处理器上的原子操作更为复杂。

 

一个线程的4种状态:

1。 新建(CPU肯定会为其分配时间片)

2。 运行

3。 阻塞

4。 死亡

 

线程被阻塞的4个原因:

1。sleep函数,使其在限定时间内被阻塞

2。等待I/O操作的完成

3。等待互斥的数据

=======

4。使用wait()挂起了该线程,只有等到broadcast()或者signal()信号才能继续执行

=======

 

有时候需要在线程处于阻塞状态下停止运行(避免死锁的发生?I guess so),因此引入中断的概念

 

从一个run()函数中非正常跳出(未达到检测isCancel的部分),会很麻烦,需要销毁与之相关的对象或者释放一些资源,这样的推出和异常

更为类似,在ZThread中,使用了Interruption的异常处理。

除了IO操作,一个线程可以从任何===阻塞====操作中中断出来。

 

互斥阻塞的代码有问题,一直没有中断(待解决)

 

 

死锁发生的条件:

1。 相互排斥,线程使用的资源至少有一个是不被共享的

2。 至少有一个进程必须持有一种资源,而且需要等待获得被其它进程所持有的资源

3。 不能以抢占的方式获得另外进程的资源,所有进程只能把释放资源当成一个正常方式

4。 出现循环等待

 

线程间的协作:

使用wait()以及condition类(使用互斥锁并且允许挂起任务)

#include <iostream> #include <cstdlib> #include <ctime> #include "zthread/Thread.h" #include "zthread/Mutex.h" #include "zthread/Guard.h" #include "zthread/Condition.h" #include "zthread/ThreadedExecutor.h" using namespace ZThread; using namespace std; // Apply jam to buttered toast: class Jammer : public Runnable { Mutex lock; Condition butteredToastReady; bool gotButteredToast; int jammed; public: Jammer() : butteredToastReady(lock) { gotButteredToast = false; jammed = 0; } void moreButteredToastReady() { Guard<Mutex> g(lock); gotButteredToast = true; butteredToastReady.signal(); } void run() { try { while(!Thread::interrupted()) { { Guard<Mutex> g(lock); while(!gotButteredToast) butteredToastReady.wait(); ++jammed; } cout << "Putting jam on toast " << jammed << endl; { Guard<Mutex> g(lock); gotButteredToast = false; } } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Jammer off" << endl; } }; // Apply butter to toast: class Butterer : public Runnable { Mutex lock; Condition toastReady; CountedPtr<Jammer> jammer; bool gotToast; int buttered; public: Butterer(CountedPtr<Jammer>& j) : toastReady(lock), jammer(j) { gotToast = false; buttered = 0; } void moreToastReady() { Guard<Mutex> g(lock); gotToast = true; toastReady.signal(); } void run() { try { while(!Thread::interrupted()) { { Guard<Mutex> g(lock); while(!gotToast) toastReady.wait(); ++buttered; } cout << "Buttering toast " << buttered << endl; jammer->moreButteredToastReady(); { Guard<Mutex> g(lock); gotToast = false; } } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Butterer off" << endl; } }; class Toaster : public Runnable { CountedPtr<Butterer> butterer; int toasted; public: Toaster(CountedPtr<Butterer>& b) : butterer(b) { toasted = 0; } void run() { try { while(!Thread::interrupted()) { Thread::sleep(rand()/(RAND_MAX/5)*100); // ... // Create new toast // ... cout << "New toast " << ++toasted << endl; butterer->moreToastReady(); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Toaster off" << endl; } }; int main() { srand(time(0)); // Seed the random number generator try { cout << "Press <Return> to quit" << endl; CountedPtr<Jammer> jammer(new Jammer); CountedPtr<Butterer> butterer(new Butterer(jammer)); ThreadedExecutor executor; executor.execute(new Toaster(butterer)); executor.execute(butterer); executor.execute(jammer); cin.get(); executor.interrupt(); } catch(Synchronization_Exception& e) { cerr << e.what() << endl; } } ///:~

                                                                                                  code1-7

 

几个需要注意的地方:

 

1. 处理的对象包括一个condition,该condition需要用对象的互斥锁来初始化。
2. 在等待下一项操作时,需要使用

                                          while(condition)
                                                  condition.wait();
3. 当产生了下一项操作所需的资源时,需要condition来调用signal()或者broadcast()函数来唤醒被挂起的进程。

 

从上述的代码中总结的一些要点:

1. 上一道工序总是持有下一道工序的指针。(为了调用其成员用来通讯)
2. 在下一道工序中,包含上一道工序是否完成的bool变量,并且包含等待上一道工序完成的成员函数。
3. 上一道工序完成之后,给下一道工序发送完成的消息,下一道工序的run()函数中有测试上一道工序是否完成的condition。

 

用队列解决线程处理的问题:

需要对任务进行串行化,即有序的处理任务,使用队列可以采用同步的方式访问其内部元素。

 

代码如下:

//: C11:TQueue.h // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) 1995-2004 MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at www.MindView.net. #ifndef TQUEUE_H #define TQUEUE_H #include <deque> #include "zthread/Thread.h" #include "zthread/Condition.h" #include "zthread/Mutex.h" #include "zthread/Guard.h" template<class T> class TQueue { ZThread::Mutex lock; ZThread::Condition cond; std::deque<T> data; public: TQueue() : cond(lock) {}//使用lock初始化condition 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())//这两行代码在含有condition的函数中是必须的~~ cond.wait(); T returnVal = data.front(); data.pop_front(); return returnVal; } }; #endif // TQUEUE_H ///:~

                                                                                                 Code1-8

 

//: C11:TestTQueue.cpp {RunByHand} // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) 1995-2004 MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at www.MindView.net. //{L} ZThread #include <string> #include <iostream> #include "TQueue.h" #include "zthread/Thread.h" #include "LiftOff.h" using namespace ZThread; using namespace std; class LiftOffRunner : public Runnable { TQueue<LiftOff*> rockets; public: void add(LiftOff* lo) { rockets.put(lo); } void run() { try { while(!Thread::interrupted()) { LiftOff* rocket = rockets.get(); rocket->run();//显式的调用run()函数 } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Exiting LiftOffRunner" << endl; } }; int main() { try { LiftOffRunner* lor = new LiftOffRunner; Thread t(lor); for(int i = 0; i < 5; i++) lor->add(new LiftOff(10, i)); cin.get(); lor->add(new LiftOff(10, 99)); cin.get(); t.interrupt(); } catch(Synchronization_Exception& e) { cerr << e.what() << endl; } } ///:~

                                                                                             Code1-9

LiftOffRunuer可以忽略同步问题,因为这些可以由TQueue解决。

1。 在每个Runnable类中代码的数量和复杂性通过队列TQueue的使用都会显著减少,保护通信等待等等操作都由TQueue

来完成,Runnable类中不在含有任何的Mutex和Condition对象。

2。 类之间的耦合程度降低到最小程度,每个类只和其TQueue通信。

 

//: C11:ToastOMaticMarkII.cpp {RunByHand} // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) 1995-2004 MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at www.MindView.net. // Solving the problems using TQueues. //{L} ZThread #include <iostream> #include <string> #include <cstdlib> #include <ctime> #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; class Toast { enum Status { DRY, BUTTERED, JAMMED }; Status status; int id; public: Toast(int idn) : status(DRY), id(idn) {} #ifdef __DMC__ // Incorrectly requires default Toast() { assert(0); } // Should never be called #endif void butter() { status = BUTTERED; } void jam() { status = JAMMED; } string getStatus() const { switch(status) { case DRY: return "dry"; case BUTTERED: return "buttered"; case JAMMED: return "jammed"; default: return "error"; } } int getId() { return id; } friend ostream& operator<<(ostream& os, const Toast& t) { return os << "Toast " << t.id << ": " << t.getStatus(); } }; typedef CountedPtr< TQueue<Toast> > ToastQueue; class Toaster : public Runnable { ToastQueue toastQueue; int count; public: Toaster(ToastQueue& tq) : toastQueue(tq), count(0) {} void run() { try { while(!Thread::interrupted()) { int delay = rand()/(RAND_MAX/5)*100; Thread::sleep(delay); // Make toast Toast t(count++); cout << t << endl; // Insert into queue toastQueue->put(t); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Toaster off" << endl; } }; // Apply butter to toast: class Butterer : public Runnable { //包含当前以及前一步骤的Thread Queue //操作都十分类似,从上一步的队列中取出 //处理完成之后再插入到当前的队列当中 ToastQueue dryQueue, butteredQueue; public: Butterer(ToastQueue& dry, ToastQueue& buttered) : dryQueue(dry), butteredQueue(buttered) {} void run() { try { while(!Thread::interrupted()) { // Blocks until next piece of toast is available: Toast t = dryQueue->get(); t.butter(); cout << t << endl; butteredQueue->put(t); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Butterer off" << endl; } }; // Apply jam to buttered toast: class Jammer : public Runnable { ToastQueue butteredQueue, finishedQueue; public: Jammer(ToastQueue& buttered, ToastQueue& finished) : butteredQueue(buttered), finishedQueue(finished) {} void run() { try { while(!Thread::interrupted()) { // Blocks until next piece of toast is available: Toast t = butteredQueue->get(); t.jam(); cout << t << endl; finishedQueue->put(t); } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Jammer off" << endl; } }; // Consume the toast: class Eater : public Runnable { ToastQueue finishedQueue; int counter; public: Eater(ToastQueue& finished) : finishedQueue(finished), counter(0) {} void run() { try { while(!Thread::interrupted()) { // Blocks until next piece of toast is available: Toast t = finishedQueue->get(); // Verify that the toast is coming in order, // and that all pieces are getting jammed: if(t.getId() != counter++ || t.getStatus() != "jammed") { cout << ">>>> Error: " << t << endl; exit(1); } else cout << "Chomp! " << t << endl; } } catch(Interrupted_Exception&) { /* Exit */ } cout << "Eater off" << endl; } }; int main() { srand(time(0)); // Seed the random number generator try { ToastQueue dryQueue(new TQueue<Toast>), butteredQueue(new TQueue<Toast>), finishedQueue(new TQueue<Toast>); cout << "Press <Return> to quit" << endl; ThreadedExecutor executor; executor.execute(new Toaster(dryQueue)); executor.execute(new Butterer(dryQueue,butteredQueue)); executor.execute( new Jammer(butteredQueue, finishedQueue)); executor.execute(new Eater(finishedQueue)); cin.get(); executor.interrupt(); } catch(Synchronization_Exception& e) { cerr << e.what() << endl; } } ///:~

                                                                                               Code1-10

 

对比Code1-8和Code1-10可以看出差别,使用TQueue的好处是显而易见的。

 

当有多个线程等待相同的一个条件时,使用broadcast()函数来代替wait()函数来执行唤醒工作。

 

一个巨长的代码例子:

//: C11:CarBuilder.cpp {RunByHand} // From "Thinking in C++, Volume 2", by Bruce Eckel & Chuck Allison. // (c) 1995-2004 MindView, Inc. All Rights Reserved. // See source code use permissions stated in the file 'License.txt', // distributed with the code package available at www.MindView.net. // How broadcast() works. //{L} ZThread #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(1000); // 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(); } // Each robot reports when their job is done: void taskFinished() { Guard<Mutex> g(readyLock); 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: //这样能够确保所有的准备工作都做好了才开始执行? //I think so~~ assemblyLine.execute(new ChassisBuilder(chassisQueue)); cin.get(); assemblyLine.interrupt(); } catch(Synchronization_Exception& e) { cerr << e.what() << endl; } } ///:~

                                                                                          Code1-11

 

关于死锁,记住产生死锁的四个条件,破坏其中的一个就能解决出现死锁的问题。

 

至此结束,任重道远~~

 

你可能感兴趣的:(thread,exception,IBM,Class,任务,permissions)