4.3.2 POSIX API的接口类(2)
其中do_something( ) = 0方法防止用户简单地声明一个thread_object对象。为了使用thread_object类,用户必须为do_something( )提供功能性,方法是继承thread_object并为do_something( )提供一个实现。在程序清单4-2的程序上下文中,do_something方法与程序清单4-2的第19行和第47行的task1及task2有相同的功能。方法do_something搜索文件,寻找MagicCode。还要注意程序清单4-4的第22行。该friend函数与do_something( )方法一起使用来为pthread_create功能提供保证。类user_thread继承thread_object类,并为do_something( )方法提供定义。注意在程序清单4-4中,user_thread类有posix_queue数据成员。这是程序清单4-2的第25行和第53行所使用的PosixQueue。这个thread_object简单示例示范了与程序清单4-2中纯过程式方法的不同之处,虽然差别不大,但的确是向着面向对象方法的改变。
图4-5显示了user_thread类的UML类关系图。
|
| 图4-5 |
迄今为止,thread_object类只是一个简单的框架类(skeleton class),我们将逐步对这个类进行定义。thread_object类还是一个接口类,它的目的是封装POSIX线程接口并提供面向对象语义和组件,从而使得我们可以更加容易地实现SDLC中产生的模型。比较图4-3和图4-5中组件的逻辑细分,显然图4-5中的焦点明显不同,因为我们是对find_code程序进行面向对象的分解。user_object定义了继承自thread_object的find_code函数。面向对象方法隐藏了图4-3中显示的实现细节。程序清单4-5包含简单了thread_object类的一些实现。
程序清单4-5
- // Listing 4-5 A definition of a simple thread_object.
-
- 1 #include "thread_object.h"
- 2
- 3
- 4 thread_object::thread_object(void)
- 5 {
- 6
- 7
- 8
- 9 }
- 10 thread_object::~thread_object(void)
- 11 {
- 12 pthread_join(Tid,NULL);
- 13 }
- 14
- 15
- 16 void thread_object::run(void)
- 17 {
- 18 pthread_create(&Tid,NULL,thread,this);
- 19 }
- 20
- 21 void thread_object::join(void)
- 22 {
- 23 pthread_join(Tid,NULL);
- 24 }
- 25
- 26
- 27 void thread_object::name(string X)
- 28 {
- 29 Name = X;
- 30 }
- 31
- 32 string thread_object::name(void)
- 33 {
- 34 return(Name);
- 35 }
- 36
- 37
- 38 void * thread (void * X)
- 39 {
- 40
- 41 thread_object *Thread;
- 42 Thread = static_cast<thread_object *>(X);
- 43 Thread->do_something();
- 44 return(NULL);
- 45
- 46
- 47 }
现在您可以看到run( )和thread( )方法如何用来共同提供pthread_create( )调用的功能。这只是开始,我们可以做得更好。注意这里没有thread_object类中声明的do_something( )方法的实现,这个方法将会在thread_object类派生子类时由用户提供。程序清单4-5中第43行的Thread->do_something( )调用将会由派生类提供的方法。在我们的示例中,这是由程序清单4-6中的定义来定义的。
程序清单 4-6
- //Listing 4-6 The definition for the user_thread class.
-
- 1 #include "thread_object.h"
- 2 #include <iostream>
- 3 #include <fstream>
- 4
- 5 bool Found = false;
- 6
- 7
- 8 user_thread::user_thread(void)
- 9 {
- 10
- 11 PosixQueue = new posix_queue("queue_name");
- 12 PosixQueue->queueFlags(O_RDONLY);
- 13 PosixQueue->messageSize(14);
- 14 PosixQueue->maxMessages(4);
- 15
- 16 }
- 17
- 18
- 19 user_thread::~user_thread(void)
- 20 {
- 21
- 22 delete PosixQueue;
- 23
- 24 }
- 25
- 26
- 27 void user_thread::do_something(void)
- 28 {
- 29 ofstream Fout;
- 30 string FileName;
- 31 string Value;
- 32
- 33 if(PosixQueue->open()){
- 34 PosixQueue->receive(FileName);
- 35 ifstream Fin(FileName.c_str());
- 36 string FileOut(FileName);
- 37 FileOut.append(".out");
- 38 Fout.open(FileOut.c_str());
- 39
- 40 while(!Fin.eof() && !Fin.fail() && !Found)
- 41 {
- 42 getline(Fin,Value);
- 43 if(!Fin.eof() && !Fin.fail() && !Found){
- 44 if(Value == MagicCode){
- 45
- 46 Found = true;
- 47
- 48 }
- 49
- 50 }
- 51 }
- 52 Fin.close();
- 53 Fout.close();
- 54 }
- 55
- 56 }
user_thread类中的主要工作是由do_something( )方法来执行的。通过覆盖do_something( )方法,我们可以使用这个user_thread类来完成通过pthread_create功能能够做的任何类型的工作。在本案例中,do_something( )方法执行文件搜索。在程序清单4-3中,user_thread对象调用的线程的run( )方法最终执行do_something( )方法。由于在第5行中定义的Found变量是一个全局变量,而且拥有文件作用域,因此一旦定位到了待搜索的值,我们就可以使用它来终止线程。
程序概要 4-4
程序名:
- user_thread.cc(程序清单4-6)
描述:
user_thread类通过do_something( )方法来完成,该方法能够做pthread_create功能所能够做的任何类型的工作。do_something( )方法用于完成文件搜索。被user_thread对象调用的线程中的run( )方法执行do_something( )方法。由于Found变量是全局的,而且有着文件作用域,它可以在定位到待搜索的值之后停止线程。
必需的库:
- pthread
需要的其他源文件:
- thread_object2.cc(程序清单4-6)
必需的用户定义头文件:
- thread_object.h(程序清单4-4)
编译指令:
- cc++ -c user_thread.cc
测试环境:
- Linux Kernel 2.6
- Solaris 10、gcc 3.4.3和gcc 3.4.6
处理器:
- Multicore Opteron、UltraSparc T1和Cell Processor
注释:
无
联合使用接口类及POSIX,使得您可以创建跨平台组件,它们有助于跨平台多线程或多处理应用程序的实现。当然,程序清单4-4中声明的thread_object接口类在能够用于生产环境之前,必须被大幅度充实。C++(www.cppentry.com)接口类广泛用于高级组件库和应用框架中,如STAPL和TBB。如果您理解了接口类如何与操作系统API结合使用,那么TBB、STAPL和操作系统之间的关系将会更明显。接口类可用来将您自己的构建块加入到TBB、STAPL以及并行处理和多线程所使用的其他高级库中。