简介
- 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++标准库提供了一种简单而强大的机制来处理多线程间的同步问题。