利用訊號量實現執行緒順序執行

Rice_rice發表於2024-06-14

執行緒順序迴圈執行的場景在多執行緒程式設計中並不罕見,尤其是在需要協調多個執行緒按特定順序重複執行任務的情況下。以下是幾個常見的例子:

  1. 生產者-消費者模型:在這種模型中,生產者執行緒生成資料並將其放入緩衝區,而消費者執行緒從緩衝區取出資料進行處理。這種情況下,生產者和消費者執行緒通常按順序交替執行。
  2. 流水線處理:在某些應用中,資料處理分為多個步驟,每個步驟由不同的執行緒負責。例如,在影像處理流水線中,可能有一個執行緒讀取影像資料,一個執行緒處理影像,一個執行緒儲存處理後的影像。每個執行緒按順序操作,形成一個迴圈處理流水線。
  3. 週期性任務排程:某些系統需要週期性地執行一組任務,例如感測器資料採集系統,每個感測器的資料採集執行緒需要按順序執行,並且在一定時間後重新開始。

為了更好地理解,我們可以透過一個具體的例子來說明如何使用訊號量和多執行緒實現順序迴圈執行。

利用POSIX無名訊號量實現三個執行緒 T1、T2 和 T3,按順序迴圈執行各自的任務。

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define NUM_ITERATIONS 3

sem_t sem1, sem2, sem3;

void* thread1(void* arg) {
    for (int i = 0; i < NUM_ITERATIONS; ++i) {
        sem_wait(&sem1);  // 等待訊號量
        printf("Thread 1 is running\n");
        sleep(1);  // 模擬工作
        printf("Thread 1 has finished\n");
        sem_post(&sem2);  // 通知thread2可以開始
    }
    return NULL;
}

void* thread2(void* arg) {
    for (int i = 0; i < NUM_ITERATIONS; ++i) {
        sem_wait(&sem2);  // 等待訊號量
        printf("Thread 2 is running\n");
        sleep(1);  // 模擬工作
        printf("Thread 2 has finished\n");
        sem_post(&sem3);  // 通知thread3可以開始
    }
    return NULL;
}

void* thread3(void* arg) {
    for (int i = 0; i < NUM_ITERATIONS; ++i) {
        sem_wait(&sem3);  // 等待訊號量
        printf("Thread 3 is running\n");
        sleep(1);  // 模擬工作
        printf("Thread 3 has finished\n");
        sem_post(&sem1);  // 通知thread1可以開始
    }
    return NULL;
}

int main() {
    pthread_t t1, t2, t3;

    // 初始化訊號量
    sem_init(&sem1, 0, 1);  // 初始訊號量為1,使執行緒1首先執行
    sem_init(&sem2, 0, 0);
    sem_init(&sem3, 0, 0);
/*
 int sem_init(sem_t *sem, int pshared, unsigned int value);
 pshared訊號量的作用範圍,0為執行緒間,非0為程序間
 value 訊號量值,首先執行的執行緒訊號量設定為1,其他的為0
*/
    // 建立執行緒
    pthread_create(&t1, NULL, thread1, NULL);
    pthread_create(&t2, NULL, thread2, NULL);
    pthread_create(&t3, NULL, thread3, NULL);

    // 等待所有執行緒完成
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);

    // 銷燬訊號量
    sem_destroy(&sem1);
    sem_destroy(&sem2);
    sem_destroy(&sem3);

    printf("All threads have finished execution.\n");

    return 0;
}

輸出結果:

Thread 1 is running
Thread 1 has finished
Thread 2 is running
Thread 2 has finished
Thread 3 is running
Thread 3 has finished
Thread 1 is running
Thread 1 has finished
Thread 2 is running
Thread 2 has finished
Thread 3 is running
Thread 3 has finished
Thread 1 is running
Thread 1 has finished
Thread 2 is running
...

相關文章