65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 线程类

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.95/5 (34投票s)

2004年1月28日

CPOL

3分钟阅读

viewsIcon

200330

downloadIcon

2411

一篇关于包装Win32线程API的文章。

引言

C++语言鼓励面向对象编程。Win32 API完全基于C语言。编写Windows平台的软件总是需要使用Win32 API。许多偏好C++和面向对象编程的开发者都希望有合适的C++类库可用,以使他们的软件具有始终如一的面向对象外观和感觉。

Java以及现在的.NET的巨大流行,主要基于构成编程平台的大量类。Java和.NET应用程序程序员只需利用这些类编写他们的应用程序,而相比之下,C++程序员首先编写基础架构,然后用它来编写应用程序。在本文中,我将向您展示如何编写一个简单的C++类来包装Win32线程相关的API。

Thread类

Java和.NET平台已经提出了一些非常好的模型,所以我们不妨使我们的模型看起来相似。这样做的好处是,任何熟悉Java或.NET的人都可以很容易地理解它。

Java和.NET中的线程模型要求线程对象接受类方法作为其线程过程。这是一个示例

Java中的线程

// define class with a threadable method
public class MyObject implements Runnable {
  // the thread procedure
  public void run() {
    // TODO: put the code here
  }
}

MyObject obj = new MyObject();
Thread thread = new Thread(obj);
tread.start();

.NET中的线程

// define class with a threadable method
public class MyObject {
  // the thread procedure
  public void Run() {
    // TODO: put the code here
  }
}

MyObject obj = new MyObject();
Thread thread = new Thread(new ThreadStart(obj.Run));
tread.Start();

这些模型非常相似。Java要求可线程化对象实现Runnable接口,而.NET某种程度上也要求这样做,因为这两个平台上的Thread类都期望可线程化过程具有以下形式:public void run()

Java规范相当简单。只有一个简单的接口公开一个简单的方法。.NET规范更加复杂。“委托”的概念为编写多线程程序提供了更大的灵活性。这是一个示例

// create a threadable object
public class MyObject {
  // first thread procedure
  public void ThreadProc1() {
    // TODO:    
  }
  // second thread procedure
  public void ThreadProc2() {
    // TODO:
  }
}

MyObject obj = new MyObject();

// create first thread
Thread thread1 = new Thread( new ThreadStart(obj.ThreadProc1) );
thread1.Start();

//create second thread
Thread thread2 = new Thread( new ThreadStart(obj.ThreadProc2) );
thread2.Start();

.NET线程模型提供了更多优势。任何与ThreadStart委托兼容的类方法都可以作为线程过程运行。如上面的代码片段所示,多个线程可以并发访问和操作单个对象实例。这是一个非常强大的功能。

我们自然希望C++线程模型像Java一样简单,像.NET一样灵活。让我们首先关注Java式的简单性。这是一个建议

// define the interface
struct IRunnable {
  virtual void run() = 0;
};

// define the thread class
class Thread {
public:
  Thread(IRunnable *ptr) {
    _threadObj = ptr;
  }
  void start() {
    // use the Win32 API here
    DWORD threadID;
    ::CreateThread(0, 0, threadProc, _threadObj, 0, &threadID);
  }
  
protected:
  // Win32 compatible thread parameter and procedure 
  IRunnable *_threadObj; 
  static unsigned long __stdcall threadProc(void* ptr) {
    ((IRunnable*)ptr)->run();
    return 0;
  }   
};

现在我们可以像Java程序员一样优雅地编写多线程程序了。

// define class with a threadable method
class MyObject : IRunnable {
public:
  // the thread procedure
  virtual void run() {
    // TODO: put the code here
  }
}

MyObject *obj = new MyObject();
Thread thread = new Thread(obj);
tread->start();

它之所以如此简单,是因为我们将Win32 API调用隐藏到一个包装类中。这里的巧妙之处在于作为我们Thread类一部分定义的静态方法。因此,我们模拟了更简单的Java Thread类。

.NET的ThreadThreadStart方法稍微难以模拟。但是我们仍然可以通过使用指向类方法的指针来实现它。这是一个例子

// define class with a threadable method
class MyObject : IRunnable {
 // pointer to a class method
 typedef void (MyObject::* PROC)();
 PROC fp;
 
 // first thread procedure
 void threadProc1() {
   //TODO: code for this thread procedure
 }
 // second thread procedure
 void threadProc2() {
   //TODO: code for this thread procedure
 }
    
public:
  MyObject() {
    fp = threadProc1;
  }
  void setThreadProc(int n) {
    if(n == 1) 
        fp = threadProc1;
    else
    if(n == 2)
        fp = threadProc2;
  }
  // the thread procedure
  virtual void run() {
    (this->*fp)();
  }
};

MyObject *obj = new MyObject();

obj->setThreadProc(1);
Thread *thread1 = new Thread(obj);
thread1->start();

obj->setThreadProc(2);
Thread *thread2 = new Thread(obj);
thread2->start();

实际的可线程化方法run()现在使用指向类方法的指针来运行相应的线程过程。在启动新线程之前,必须正确初始化该指针。

结论

将Win32 API包装到C++类中是首选方法。Java和.NET平台为我们提供了定义良好的模型。相比之下,这些模型非常相似,因此为线程类、套接字类、流类等定义C++类应该只是遵循提供的文档的问题。

您可以下载Thread类并试用它。我设计它尽可能简单,但您可以通过包装其他一些与线程相关的API来增强它,例如SetThreadPriority, GetThreadPriority等。

© . All rights reserved.