Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Đa luồng (Multithreading) trong C++

Đa luồng (Multithreading) là dạng chuyên biệt của đa nhiệm (multitasking), và đa nhiệm là tính năng cho phép máy tính chạy hai hoặc nhiều chương trình cùng lúc. Nói chung, có hai loại đa nhiệm: dựa trên tiến trình (process-based) và dựa trên luồng (thread-based).

Đa nhiệm dựa trên tiến trình xử lý thực thi đồng thời các chương trình. Đa nhiệm dựa trên luồng xử lý thực thi đồng thời các phần của cùng một chương trình.

Chương trình đa luồng chứa hai hoặc nhiều phần có thể chạy đồng thời. Mỗi phần gọi là một luồng (thread), và mỗi luồng định nghĩa một đường dẫn thực thi riêng biệt.

C++ không có hỗ trợ tích hợp sẵn cho ứng dụng đa luồng. Thay vào đó, nó hoàn toàn phụ thuộc vào hệ điều hành để cung cấp tính năng này.

Hướng dẫn này giả định bạn đang làm việc trên Linux OS và chúng ta sẽ viết chương trình C++ đa luồng sử dụng POSIX. POSIX Threads (Pthreads) cung cấp API có sẵn trên nhiều hệ thống Unix-like như FreeBSD, NetBSD, GNU/Linux, Mac OS X và Solaris.

Hàm sau dùng để tạo luồng POSIX:

#include <pthread.h>
pthread_create(thread, attr, start_routine, arg)

Ở đây, pthread_create tạo luồng mới và làm cho nó có thể thực thi. Hàm này có thể gọi bao nhiêu lần tùy ý từ bất kỳ đâu trong code. Mô tả tham số:

Tham sốMô tả
threadĐịnh danh mờ, duy nhất cho luồng mới trả về bởi subroutine.
attrĐối tượng thuộc tính mờ, có thể dùng để đặt thuộc tính luồng. Có thể chỉ định đối tượng thuộc tính luồng, hoặc NULL cho giá trị mặc định.
start_routineHàm C++ mà luồng sẽ thực thi sau khi được tạo.
argTham số đơn có thể truyền cho start_routine. Phải truyền bằng tham chiếu dưới dạng con trỏ ép kiểu void. NULL có thể dùng nếu không cần truyền tham số.

Số lượng luồng tối đa có thể tạo bởi một tiến trình phụ thuộc vào triển khai. Sau khi tạo, các luồng là ngang hàng (peers), và có thể tạo luồng khác. Không có thứ bậc hay phụ thuộc ngầm định giữa các luồng.

Kết thúc luồng

Có hàm sau để kết thúc luồng POSIX:

#include <pthread.h>
pthread_exit(status)

Ở đây pthread_exit dùng để thoát rõ ràng một luồng. Thông thường, pthread_exit() được gọi sau khi luồng hoàn thành công việc và không còn cần thiết.

Nếu main() kết thúc trước các luồng nó tạo, và thoát với pthread_exit(), các luồng khác sẽ tiếp tục thực thi. Ngược lại, chúng sẽ tự động bị chấm dứt khi main() kết thúc.

Ví dụ

#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;

#define NUM_THREADS 5

void *PrintHello(void *threadid) {
    long tid;
    tid = (long)threadid;
    cout << "Hello World! Thread ID, " << tid << endl;
    pthread_exit(NULL);
}

int main () {
    pthread_t threads[NUM_THREADS];
    int rc;
    int i;
    for( i = 0; i < NUM_THREADS; i++ ) {
        cout << "main() : creating thread, " << i << endl;
        rc = pthread_create(&threads[i], NULL, PrintHello, (void *)i);
        if (rc) {
            cout << "Error:unable to create thread," << rc << endl;
            exit(-1);
        }
    }
    pthread_exit(NULL);
}

Kết quả

$gcc test.cpp -lpthread
$./a.out
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Hello World! Thread ID, 0
Hello World! Thread ID, 1
Hello World! Thread ID, 2
Hello World! Thread ID, 3
Hello World! Thread ID, 4