溫馨提示×

Linux C++中如何使用信號量

小樊
61
2025-04-28 06:36:11
欄目: 編程語言

在 Linux 下使用 C++ 進行信號量(semaphore)編程,通常涉及 POSIX 信號量(POSIX semaphores)。POSIX 信號量提供了一種用于進程間同步或線程間同步的機制。以下是如何在 C++ 中使用 POSIX 信號量的基本指南,包括創建、操作和銷毀信號量。

POSIX 信號量的基本概念

POSIX 信號量分為兩種類型:

  1. 命名信號量(Named Semaphores):通過名稱進行標識,可以在不同進程之間共享。
  2. 未命名信號量(Unnamed Semaphores):通常用于線程間同步,存儲在內存中。

本文將重點介紹命名信號量的使用方法。

使用步驟

  1. 包含必要的頭文件
  2. 創建或打開信號量
  3. 初始化信號量
  4. 執行 P 操作(等待)和 V 操作(釋放)
  5. 銷毀信號量

示例代碼

下面是一個使用命名 POSIX 信號量的示例程序,演示了如何在多個進程之間同步對共享資源的訪問。

1. 創建一個共享內存段和信號量

首先,創建一個共享內存段,并在其中放置一個信號量。這里我們使用 shm_open 創建命名共享內存,并使用 sem_init 初始化信號量。

// semaphore_example.cpp
#include <iostream>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
#include <cstring>

// 定義信號量和共享內存的名稱
const char* SEM_NAME = "/my_semaphore";
const char* SHM_NAME = "/my_shared_memory";

int main() {
    // 創建或打開信號量
    sem_t* sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
    if (sem == SEM_FAILED) {
        perror("sem_open");
        return EXIT_FAILURE;
    }

    // 創建或打開共享內存
    int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0644);
    if (shm_fd == -1) {
        perror("shm_open");
        sem_close(sem);
        return EXIT_FAILURE;
    }

    // 設置共享內存大小
    if (ftruncate(shm_fd, sizeof(int)) == -1) {
        perror("ftruncate");
        close(shm_fd);
        sem_close(sem);
        return EXIT_FAILURE;
    }

    // 映射共享內存
    int* shared_value = static_cast<int*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));
    if (shared_value == MAP_FAILED) {
        perror("mmap");
        close(shm_fd);
        sem_close(sem);
        return EXIT_FAILURE;
    }

    // 初始化共享資源
    *shared_value = 0;
    std::cout << "Shared resource initialized to " << *shared_value << std::endl;

    // 關閉共享內存映射
    munmap(shared_value, sizeof(int));

    // 示例操作:多個進程對共享資源進行增減操作
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        close(shm_fd);
        sem_close(sem);
        return EXIT_FAILURE;
    } else if (pid == 0) { // 子進程
        // 等待信號量
        if (sem_wait(sem) == -1) {
            perror("sem_wait");
            close(shm_fd);
            sem_close(sem);
            return EXIT_FAILURE;
        }

        // 訪問共享資源
        shared_value = static_cast<int*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));
        if (shared_value == MAP_FAILED) {
            perror("mmap");
            close(shm_fd);
            sem_close(sem);
            return EXIT_FAILURE;
        }

        (*shared_value)++;
        std::cout << "Child process incremented shared value to " << *shared_value << std::endl;

        munmap(shared_value, sizeof(int));
        // 釋放信號量
        if (sem_post(sem) == -1) {
            perror("sem_post");
        }

        close(shm_fd);
        sem_close(sem);
        return EXIT_SUCCESS;
    } else { // 父進程
        // 等待信號量
        if (sem_wait(sem) == -1) {
            perror("sem_wait");
            close(shm_fd);
            sem_close(sem);
            return EXIT_FAILURE;
        }

        // 訪問共享資源
        shared_value = static_cast<int*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));
        if (shared_value == MAP_FAILED) {
            perror("mmap");
            close(shm_fd);
            sem_close(sem);
            return EXIT_FAILURE;
        }

        (*shared_value)--;
        std::cout << "Parent process decremented shared value to " << *shared_value << std::endl;

        munmap(shared_value, sizeof(int));
        // 釋放信號量
        if (sem_post(sem) == -1) {
            perror("sem_post");
        }

        close(shm_fd);
        sem_close(sem);

        // 等待子進程結束
        wait(NULL);
    }

    return EXIT_SUCCESS;
}

2. 編譯程序

使用 g++ 編譯上述代碼:

g++ -o semaphore_example semaphore_example.cpp

3. 運行程序

首先運行程序,它將創建共享內存和信號量:

./semaphore_example

輸出示例:

Shared resource initialized to 0
Parent process decremented shared value to -1
Child process incremented shared value to 0

在這個示例中:

  • 父進程和子進程通過信號量同步對共享資源的訪問。
  • 使用 sem_wait(相當于 P 操作)等待信號量,確?;コ庠L問。
  • 使用 sem_post(相當于 V 操作)釋放信號量,允許其他進程訪問共享資源。

詳細說明

1. 創建或打開信號量

sem_t* sem = sem_open(SEM_NAME, O_CREAT, 0644, 1);
  • SEM_NAME:信號量的名稱,所有需要訪問該信號量的進程必須使用相同的名稱。
  • O_CREAT:如果信號量不存在,則創建它。
  • 0644:權限模式,類似于文件權限。
  • 1:初始值,表示信號量的計數。

2. 初始化共享內存

int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0644);
ftruncate(shm_fd, sizeof(int));
int* shared_value = static_cast<int*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0));
*shared_value = 0;
  • 使用 shm_open 創建或打開共享內存對象。
  • 使用 ftruncate 設置共享內存的大小。
  • 使用 mmap 將共享內存映射到進程的地址空間。
  • 初始化共享資源(例如,一個整數)。

3. 執行 P 操作和 V 操作

sem_wait(sem); // P 操作:等待信號量,計數減一
// 訪問共享資源
sem_post(sem); // V 操作:釋放信號量,計數加一
  • sem_wait:減少信號量的計數。如果計數為零,調用進程將被阻塞,直到有其他進程調用 sem_post 增加計數。
  • sem_post:增加信號量的計數,并喚醒一個等待的進程(如果有)。

4. 銷毀信號量

當不再需要信號量時,應該銷毀它以釋放資源:

sem_close(sem);
sem_unlink(SEM_NAME);
  • sem_close:關閉信號量的描述符。
  • sem_unlink:刪除命名信號量,只有當引用計數為零時才會真正刪除。

注意事項

  1. 同步機制選擇

    • 如果僅在單個進程的多個線程之間同步,可以考慮使用 C++11 提供的線程同步機制,如 std::mutex、std::condition_variable 等,更加方便和安全。
    • POSIX 信號量適用于跨進程的同步。
  2. 錯誤處理

    • 始終檢查系統調用的返回值,并進行適當的錯誤處理。
  3. 資源管理

    • 確保在不再需要時關閉信號量和共享內存,避免資源泄漏。
    • 使用 sem_unlink 刪除命名信號量,防止僵尸信號量占用系統資源。
  4. 原子性操作

    • 信號量的 P 和 V 操作是原子的,確保了對共享資源的互斥訪問。

使用 C++11 線程同步(可選)

如果你的應用僅涉及多線程同步,推薦使用 C++11 提供的同步機制,因為它們更易于使用且與 C++ 語言集成更好。例如:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;
int shared_value = 0;

void increment() {
    std::lock_guard<std::mutex> lock(mtx);
    ++shared_value;
    std::cout << "Incremented to " << shared_value << std::endl;
}

void decrement() {
    std::lock_guard<std::mutex> lock(mtx);
    --shared_value;
    std::cout << "Decremented to " << shared_value << std::endl;
}

int main() {
    std::thread t1(increment);
    std::thread t2(decrement);

    t1.join();
    t2.join();

    return 0;
}

使用 std::mutexstd::lock_guard 可以簡化同步操作,避免手動管理鎖的獲取和釋放。

總結

POSIX 信號量是一種強大的進程間和線程間同步機制,適用于需要跨進程訪問共享資源的場景。通過正確地創建、操作和銷毀信號量,可以有效地控制對共享資源的訪問,防止競態條件和數據不一致的問題。然而,對于僅涉及多線程同步的應用,C++11 提供的同步機制更加簡潔和高效,推薦優先使用。

0
亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女