- 互斥锁(Mutex)
原理:
互斥锁用于保护共享资源,确保在同一时刻只有一个线程能够访问被保护的资源。当一个线程想要访问共享资源时,它首先尝试获取互斥锁。如果锁已经被其他线程持有,那么该线程会被阻塞,直到锁被释放。一旦获取到锁,线程就可以安全地访问共享资源,访问结束后再释放锁,以便其他线程能够获取锁并访问资源。
示例代码:
cpp
复制
#include <iostream>
#include <thread>
#include <mutex>
// 定义一个互斥锁
std::mutex mutex_f;
// 共享资源,这里是一个简单的整数变量
int shared_resource = 0;
// 线程函数,用于对共享资源进行操作
void increment_resource() {
// 获取互斥锁
std::lock_guard<std::mutex> guard(mutex_f);
// 对共享资源进行操作
shared_resource++;
// 释放互斥锁(由lock_guard的析构函数自动完成)
}
int main() {
// 创建两个线程
std::thread t1(increment_resource);
std::thread t2(increment_resource);
// 等待线程完成
t1.join();
t2.join();
// 输出共享资源的值
std::cout << "Shared resource value: " << shared_resource << std::endl;
return 0;
}
在上述示例中,通过std::lock_guard来自动管理互斥锁的获取和释放,确保在increment_resource函数中对共享资源shared_resource的操作是线程安全的。
2. 条件变量(Condition Variable)
原理:
条件变量通常与互斥锁一起使用,用于让一个线程等待某个特定条件的满足。线程首先获取互斥锁,然后检查条件是否满足。如果条件不满足,线程会释放互斥锁并进入等待状态,直到被其他线程通过通知机制唤醒。被唤醒后,线程会再次获取互斥锁并重新检查条件是否满足,只有当条件满足时才会继续执行后续操作。
示例代码:
cpp
复制
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
// 定义互斥锁和条件变量
std::mutex mutex_g;
std::condition_variable condition_g;
// 共享资源,这里是一个简单的整数变量
int shared_resource_g = 0;
// 用于标识条件是否满足的标志
bool condition_met = false;
// 线程函数,用于增加共享资源的值并在满足条件时通知其他线程
void increment_and_notify() {
// 获取互斥锁
std::lock_guard<std::mutex> guard(mutex_g);
// 对共享资源进行操作
shared_resource_g++;
// 当共享资源的值达到一定程度时,设置条件满足标志并通知其他线程
if (shared_resource_g >= 5) {
condition_met = true;
condition_g.notify_all();
}
}
// 线程函数,用于等待条件满足
void wait_for_condition() {
// 获取互斥锁
std::unique_lock<std::mutex> lock(mutex_g);
// 等待条件满足,当条件不满足时释放互斥锁并进入等待状态
condition_g.wait(lock, []{ return condition_met; });
// 条件满足后,输出相关信息
std::cout << "Condition met, shared resource value: " << shared_resource_g << std::endl;
}
int main() {
// 创建两个线程
std::thread t1(increment_and_notify);
std::thread t2(wait_for_condition);
// 等待线程完成
t1.join();
t2.join();
return 0;
}
在上述示例中,increment_and_notify线程负责增加共享资源的值,并在满足特定条件(shared_resource_g >= 5)时通知其他线程。wait_for_condition线程则通过条件变量等待条件满足,在条件满足后输出相关信息。
3. 信号量(Semaphore)
原理:
信号量是一种用于控制对共享资源访问的计数器。它有一个初始值,表示可用资源的数量。当一个线程想要访问共享资源时,它会先尝试获取信号量。如果信号量的值大于 0,线程就可以获取信号量(即将信号量的值减 1)并访问共享资源。访问结束后,线程会释放信号量(即将信号量的值加 1),以便其他线程能够获取信号量并访问资源。如果信号量的值为 0,线程会被阻塞,直到有其他线程释放信号量。
示例代码:
cpp
复制
#include <iostream>
#include <thread>
#include <semaphore.h>
// 定义一个信号量,并设置初始值为3,表示有3个可用资源
sem_t semaphore_h;
// 共享资源,这里简单地用一个整数变量表示
int shared_resource_h = 0;
// 线程函数,用于获取信号量、访问共享资源并释放信号量
void access_shared_resource() {
// 获取信号量
sem_wait(&semaphore_h);
// 对共享资源进行操作
shared_resource_h++;
// 释放信号量
sem_post(&semaphore_h);
// 输出相关信息
std::cout << "Accessed shared resource, current value: " << shared_resource_h << std::endl;
}
int main() {
// 初始化信号量
sem_init(&semaphore_h, 0, 3);
// 创建三个线程
std::thread t1(access_shared_resource);
std::thread t2(access_shared_resource);
std::thread t3(access_shared_resource);
// 等待线程完成
t1.join();
t2.join();
t3.join();
// 销毁信号量
sem_destroy(&semaphore_h);
return 0;
}
在上述示例中,通过sem_wait获取信号量,sem_post释放信号量,实现了对共享资源shared_resource_h的线程安全访问。
4. 读写锁(Read-Write Lock)
原理:
读写锁用于区分对共享资源的读操作和写操作。多个线程可以同时进行读操作,因为读操作不会改变共享资源的状态。但是,当有一个线程进行写操作时,其他线程无论是读还是写都不能同时进行,必须等待写操作完成。读写锁通过维护读锁和写锁的状态来实现这种区分。
示例代码:
cpp
复制
#include <iostream>
#include <thread>
#include <shared_mutex>
// 定义一个读写锁
std::shared_mutex read_write_lock_i;
// 共享资源,这里是一个简单的整数变量
int shared_resource_i = 0;
// 线程函数,用于进行读操作
void read_shared_resource() {
// 获取读锁
std::shared_lock<std::shared_mutex> read_lock(read_write_lock_i);
// 对共享资源进行读操作
std::cout << "Read shared resource value: " << shared_resource_i << std::endl;
// 释放读锁(由shared_lock的析构函数自动完成)
}
// 线程函数,用于进行写操作
void write_shared_resource() {
// 获取写锁
std::unique_lock<std::shared_mutex> write_lock(read_write_lock_i);
// 对共享资源进行写操作
shared_resource_i++;
// 释放写锁(由unique_lock的析构函数自动完成)
}
int main() {
// 创建三个线程进行读操作,一个线程进行写操作
std::thread t1(read_shared_resource);
std::thread t2(read_shared_resource);
std::thread t3(read_shared_resource);
std::thread t4(write_shared_resource);
// 等待线程完成
t1.join();
t2.join();
t3.join();
t4.join();
return 0;
}
在上述示例中,通过std::shared_lock获取读锁进行读操作,通过std::unique_lock获取写锁进行写操作,实现了对共享资源shared_resource_i的读写操作的线程安全管理。
5. 原子类型(Atomic Types)
原理:
原子类型是 C++11 及以后引入的一种数据类型,它允许对其进行原子操作,即这些操作在多线程环境下是不可分割的,要么完整执行,要么不执行,不存在中间状态被其他线程看到的情况。常见的原子类型有std::atomic
示例代码:
cpp
复制
#include <iostream>
#include <thread>
#include <atomic>
// 定义一个原子类型的整数变量
std::atomic<int> atomic_shared_resource_j(0);
// 线程函数,用于对原子类型的共享资源进行操作
void increment_atomic_resource() {
// 对原子类型的共享资源进行操作
atomic_shared_resource_j++;
// 输出相关信息
std::cout << "Atomic shared resource value: " << atomic_shared_resource_j.load() << std::endl;
}
int main() {
// 创建两个线程
std::thread t1(increment_atomic_resource);
std::thread t2(increment_atomic_resource);
// 等待线程完成
t1.join();
t2.join();
return 0;
}
在上述示例中,通过使用std::atomic