Vietnamese Developers’ Blog

POSIX Thread (3)

Posted in Unix/Linux/BSD by Hoang Tran on October 24, 2007

Vậy là chúng ta đã quen với một số hàm cơ bản trong việc tạo và kết thúc thread.

#include <pthread.h>

int pthread_create( pthread_t *restrict thread, const pthread_attr_t *restrict attr,
                    void *(*start_routine)(void*), void *restrict arg);

void pthread_exit(void *value_ptr);

int pthread_join(pthread_t thread, void **value_ptr);

Một thread được tạo ra sẽ bắt đầu thực hiện đoạn mã trong hàm start_routine() (trong ví dụ trước là hàm thread_function) và kết thúc khi trả về hàm đó. Có thể thấy chúng ta truyền con trỏ hàm (function pointer) tới start_routine vào pthread_create. Tuy nhiên tư tưởng lập trình hướng đối tượng không thích hợp cho những hàm kiểu vậy. Chúng ta thích khởi tạo một thread mới bằng cách tạo ra một instance hay một object của một class nào đó và thực thi bằng cách gọi một member function của object đó. Ví dụ như ta có một class Task, và muốn mỗi đối tượng Task chạy trong một thread mới và thread đó sẽ tự động thực thi member function execute() của đối tượng đó. Nói một mặt nào đó gần như chúng ta muốn tạo ra một function object.

class Task
{
    public:
        virtual void execute() {};
};

Task* a = new Task();

Thế nhưng không thể truyền phương thức execute() như là tham số cho hàm pthread_create được bởi vì hàm execute bản thân nó có một tham số là con trỏ tới object chứa nó (con trỏ this) và như vậy sẽ khác prototype với hàm start_routine trong tham số trên. Chỉ với static member function thì mới không chứa tham số là con trỏ tới đối tượng đó. Như vậy chỉ có cách chúng ta truyền một static member function như tham số của pthread_create.

class Task
{
    public:
        static void* start( void* arg ) {}
        virtual void execute() {};
};

Khi đó ta có thể tạo create mới như sau:

pthread_t athread;
Task      atask;

pthread_create( athread, NULL, Task::start, NULL);

Hây khoan vậy thì chẳng liên quan gì đến cái atask cả. Chúng ta muốn một thread mới sẽ gọi execute của atask cơ mà: atask.execute(). Làm thế nào để truyền được atask vào trong hàm start? Rất đơn giản, hãy làm cái chúng ta đã nghĩ, truyền con trỏ vào atask như là tham số cho hàm start().

Task* ptask; // pointer to a task.

pthread_create( athread, NULL, Task::start, ptask) // truyền con trỏ ptask như là tham số cho hàm Task::start.

Khi đó chỉ cần ép kiểu về Task* trong hàm start là ta có thể lấy object *ptask rồi.

void* start( void* arg )
{
    Task* _ptask = (Task*) arg;
    _ptask.execute();   // execute
}

Vậy là chúng ta đã có một object như ý mà đoạn mã thực thi chạy trên một thread mới.

(Còn tiếp)

Tagged with: , ,

Leave a Reply