简介

  • C++ 标准库 详解

C++ 标准库 详解

在C++20标准中引入了 <semaphore> 头文件,提供了信号量(Semaphore)的标准库实现。信号量是一种经典的同步原语,用于控制对共享资源的访问。

创建信号量

使用 std::counting_semaphore 来创建一个计数信号量,或者使用 std::binary_semaphore 来创建一个二进制信号量。计数信号量允许指定一个初始计数值,而二进制信号量的初始状态是锁定的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <semaphore>

std::counting_semaphore

```cpp
#include <semaphore>

std::counting_semaphore

```cpp
#include <semaphore>

std::counting_semaphore

### 使用计数信号量

```cpp
#include <iostream>
#include <thread>
#include <semaphore>

std::counting_semaphore<int> mySemaphore(1); // 创建一个初始计数值为1的计数信号量

void worker(int id) {
    mySemaphore.acquire();
    std::cout << "Worker " << id << " is working..." << std::endl;
    // Simulate some work
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Worker " << id << " finished." << std::endl;
    mySemaphore.release();
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    t1.join();
    t2.join();
    return 0;
}

使用二进制信号量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>
#include <semaphore>

std::binary_semaphore mySemaphore(1); // 创建一个初始状态为1的二进制信号量

void worker(int id) {
    mySemaphore.acquire();
    std::cout << "Worker " << id << " is working..." << std::endl;
    // Simulate some work
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Worker " << id << " finished." << std::endl;
    mySemaphore.release();
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    t1.join();
    t2.join();
    return 0;
}

这里有两种信号量,一种是计数信号量,另一种是二进制信号量。计数信号量允许多个线程同时访问共享资源,而二进制信号量一次只允许一个线程访问共享资源。

标准库的信号量实现提供了一个简单而强大的工具,用于管理多线程环境中的资源访问。

C++ std::semaphore 详解

在C++20中,标准库引入了信号量 (std::semaphore)。信号量是一种经典的同步原语,用于控制多个线程对共享资源的访问。让我们详细了解一下 std::semaphore

创建信号量

你可以使用 std::semaphore 的构造函数来创建一个信号量。构造函数需要一个参数,即初始的信号量计数值。

1
2
3
#include <semaphore>

std::semaphore mySemaphore(1); // 创建一个初始计数值为1的信号量

P 操作(等待)

当一个线程想要访问共享资源时,它必须执行 P 操作,也称为等待操作。如果信号量的计数值大于 0,则计数值减 1,线程继续执行。如果计数值为 0,则线程被阻塞,直到有其他线程执行 V 操作(释放)来增加计数值。

1
mySemaphore.acquire(); // 等待(等同于 P 操作)

V 操作(释放)

当一个线程完成对共享资源的访问时,它执行 V 操作,也称为释放操作。这会增加信号量的计数值,并唤醒等待的线程(如果有的话)。

1
mySemaphore.release(); // 释放(等同于 V 操作)

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <thread>
#include <semaphore>

std::semaphore mySemaphore(1); // 创建一个初始计数值为1的信号量

void worker(int id) {
    mySemaphore.acquire();
    std::cout << "Worker " << id << " is working..." << std::endl;
    // Simulate some work
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Worker " << id << " finished." << std::endl;
    mySemaphore.release();
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);
    t1.join();
    t2.join();
    return 0;
}

在这个示例中,两个线程共享一个信号量 mySemaphore。只有一个线程能够获得信号量,另一个线程必须等待,直到第一个线程释放信号量。

注意事项

  • 如果信号量的计数值小于0,acquire() 将会阻塞当前线程。
  • release() 会递增信号量的计数值,并唤醒一个等待的线程(如果有)。
  • 使用信号量时,要注意正确地保证计数值的增减,以免造成死锁或者资源泄漏。

通过 std::semaphore,C++标准库提供了一种简单而强大的机制来处理多线程间的同步问题。