您的位置:首页 > 游戏 > 手游 > 中国建设网官方网站下载e路_永久免费补单系统_广州白云区新闻头条最新消息今天_微信社群营销推广方案

中国建设网官方网站下载e路_永久免费补单系统_广州白云区新闻头条最新消息今天_微信社群营销推广方案

2025/2/24 9:25:54 来源:https://blog.csdn.net/2301_79881188/article/details/145795831  浏览:    关键词:中国建设网官方网站下载e路_永久免费补单系统_广州白云区新闻头条最新消息今天_微信社群营销推广方案
中国建设网官方网站下载e路_永久免费补单系统_广州白云区新闻头条最新消息今天_微信社群营销推广方案

mutex

std::mutex 是C++标准库中用于线程同步的互斥锁机制,主要用于保护共享资源,避免多个线程同时访问导致的竞态条件。

它提供了以下功能:

  • 加锁(lock:阻塞当前线程,直到获取锁。

  • 解锁(unlock:释放锁,允许其他线程获取锁。

  • 尝试加锁(try_lock:尝试获取锁,如果锁已被占用则立即返回。

使用全局锁案例

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx; // 定义一个全局互斥锁
int shared_data = 0;void increment() {for (int i = 0; i < 10000; i++) {mtx.lock(); // 加锁shared_data++;mtx.unlock(); // 解锁}
}int main() {thread t1(increment);thread t2(increment);t1.join();t2.join();cout << "共享数据: " << shared_data << endl; // 输出应该是20000return 0;
}

使用传参锁案例

如果线程对象传参给可调⽤对象时,使⽤引⽤⽅式传参,实参位置需要加上ref(obj)的⽅式,主要原因是thread本质还是系统库提供的线程API的封装,thread 构造取到参数包以后,要调⽤创建线程的API,还是需要将参数包打包成⼀个结构体传参过去,那么打包成结构体时,参考包对象就会拷⻉给结构体对象,使⽤ref传参的参数,会让结构体中的对应参数成员类型推导为引⽤,这样才能实现引⽤传参。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int shared_data = 0;void increment(mutex& mtx) {for (int i = 0; i < 10000; i++) {mtx.lock(); // 加锁shared_data++;mtx.unlock(); // 解锁}
}int main() {mutex mtx; // 使用传参互斥锁thread t1(increment,ref(mtx));//需要使用 ref 包装锁,不然会报错thread t2(increment,ref(mtx));t1.join();t2.join();cout << "共享数据: " << shared_data << endl; // 输出应该是20000return 0;
}

timed_mutex

std::timed_mutex 是C++11引入的一种互斥锁类型,用于多线程编程中控制对共享资源的并发访问。它提供了超时机制,允许线程在尝试获取锁时设置一个时间限制,从而避免无限等待锁释放,降低死锁风险。

timed_mutex 跟 mutex完全类似,只是额外提供 try_lock_for 和 try_lock_untile 的接⼝,这两个接⼝跟 try_lock 类似,只是他不会⻢上返回,⽽是直接进⼊阻塞,直到时间条件到了或者解锁了就会唤醒试图获取锁资源。
  • try_lock_for(duration):尝试在指定的时间内获取锁,如果超时则返回 false

  • try_lock_until(time_point):尝试在指定的时间点之前获取锁,如果超时则返回 false。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;
timed_mutex mtx;void func(int id) {chrono::seconds timeout(3); // 设置超时时间为3秒if (mtx.try_lock_for(timeout)) {cout << "线程 " << id << " 成功获取锁,执行临界区代码..." << endl;this_thread::sleep_for(chrono::seconds(5)); // 模拟工作负载mtx.unlock();}else {cout << "线程 " << id << " 超时未能获取锁,继续执行其他任务..." << endl;}
}int main() {thread t1(func, 1);thread t2(func, 2);t1.join();t2.join();return 0;
}

recursive_mutex

recursive_mutex 跟 mutex 完全类似,允许同一个线程多次获取锁而不会导致死锁,这种互斥锁特别适用于递归函数或嵌套调用的场景。 recursive_mutex 提供排他性递归所有权语义:
  1. 调⽤⽅线程在从它成功调⽤ lock 或 try_lock 开始的时期⾥占有 recursive_mutex。此时期之内,线程可以进⾏对 lock 或 try_lock 的附加调⽤。所有权的时期在线程进⾏匹配次数的 unlock 调⽤时结束。
  2. 线程占有 recursive_mutex 时,若其他所有线程试图要求 recursive_mutex 的所有权,则它们将阻塞(对于调⽤ lock)或收到 false 返回值(对于调⽤ try_lock)。
#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
recursive_mutex rec_mutex;void recursiveFunction(int count) {if (count <= 0) return;rec_mutex.lock();cout << "Lock acquired. Count: " << count << endl;// 递归调用recursiveFunction(count - 1);rec_mutex.unlock();cout << "Lock released. Count: " << count << endl;
}int main() {thread t(recursiveFunction, 3);t.join();return 0;
}

lock_guard

std::lock_guard 是 C++ 标准库中用于管理互斥锁的 RAII(Resource Acquisition Is Initialization,资源获取即初始化)工具。它通过构造函数自动获取互斥锁,并在析构函数中自动释放锁,从而确保互斥锁的正确管理,避免因忘记解锁而导致的死锁问题。

主要特性

  1. 自动管理锁:通过构造函数获取锁,析构函数释放锁,无需手动调用 lock()unlock()

  2. 防止死锁:确保即使在异常情况下也能正确释放锁。

  3. 不可移动和复制:std::lock_guard 不支持拷贝或移动构造,确保锁的唯一性。

构造函数

explicit lock_guard(MutexType& mutex, std::adopt_lock_t tag = std::defer_lock);
  • MutexType& mutex:要管理的互斥锁对象,如mutex,timed_mutex,recersive_mutex。

  • std::adopt_lock_t tag:可选参数,表示当前线程已经持有锁,默认值是 std::defer_lock,表示 lock_guard 会在构造时自动尝试加锁。如果传入 std::adopt_lock,则表示当前线程已经通过其他方式(例如 std::lock 或手动调用 lock())持有锁,lock_guard 不会再次尝试加锁,而是直接接管锁的管理。

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx;
void print_block(int n, char c) {lock_guard<mutex> lock(mtx);  // 默认加锁,无需手动解锁for (int i = 0; i < n; ++i) {cout << c;}cout << '\n';
}int main() {thread t1(print_block, 50, '*');thread t2(print_block, 50, '$');t1.join();t2.join();return 0;
}

unique_lock

unique_lock也是C++11提供的⽀持RAII⽅式管理互斥锁资源的类,相⽐ lock_guard 他的功能⽀持
更丰富复杂。

主要特性

  1. 延迟加锁:可以在构造时不立即加锁,而是通过显式调用 lock()unlock() 来控制锁的获取和释放。

  2. 支持条件变量:可以与 std::condition_variable 配合使用,支持线程间的同步。

  3. 可选锁管理:可以选择是否持有锁,或者在构造时直接接管已持有的锁。

  4. 支持多种互斥锁类型:可以与 std::mutexstd::recursive_mutexstd::timed_mutexstd::shared_mutex 配合使用。

构造函数

template <typename Mutex>
unique_lock() noexcept;  // 默认构造,不绑定任何锁template <typename Mutex>
explicit unique_lock(Mutex& m, std::defer_lock_t);  // 延迟加锁template <typename Mutex>
unique_lock(Mutex& m, std::try_to_lock_t);  // 尝试加锁,失败时不阻塞template <typename Mutex>
unique_lock(Mutex& m, std::adopt_lock_t);  // 假设已持有锁,不加锁template <typename Mutex>
unique_lock(Mutex& m);  // 默认加锁template <typename Mutex>
unique_lock(Mutex& m, std::unique_lock<Mutex>&& other);  // 移动构造

主要成员函数

  1. lock():尝试加锁,如果锁已被占用则阻塞。

  2. try_lock():尝试加锁,如果锁已被占用则立即返回 false

  3. unlock():释放锁。

  4. owns_lock():检查是否持有锁。

  5. mutex():获取绑定的互斥锁对象。

  6. release():释放锁的所有权,但不释放锁本身。

  7. swap():交换两个 std::unique_lock 的状态。

lock和try_lock

lock是⼀个函数模板,可以⽀持对多个锁对象同时锁定,如果其中⼀个锁对象没有锁住,lock函数
会把已经锁定的对象解锁⽽进⼊阻塞,直到锁定所有的所有的对象,它的主要目的是避免死锁问题,通过一次性尝试锁定多个锁,确保所有锁都被成功锁定后才返回。
try_lock也是⼀个函数模板,尝试对多个锁对象进⾏同时尝试锁定,如果全部锁对象都锁定了,返 回-1,如果某⼀个锁对象尝试锁定失败,把已经锁定成功的锁对象解锁,并则返回这个对象的下标
(第⼀个参数对象,下标从0开始算)。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
mutex mtx1;
mutex mtx2;
void worker() {lock(mtx1, mtx2);  // 同时锁定两个锁unique_lock<mutex> lock1(mtx1, std::adopt_lock);  // 需要创建 unique_lock 自动释放锁unique_lock<mutex> lock2(mtx2, std::adopt_lock);cout << "线程进入临界区..." << endl;this_thread::sleep_for(chrono::seconds(1));  // 模拟工作负载cout << "线程退出临界区..." << endl;
}int main() {thread t1(worker);thread t2(worker);t1.join();t2.join();return 0;
}

call_once

std::call_once 是 C++11 引入的一个函数模板,用于确保某个操作(如初始化或配置加载)在多线程环境中只被调用一次。它结合了 std::once_flag,能够高效地实现线程安全的单次执行。

基本用法

std::call_once 的函数原型如下:

template <class Callable, class... Args>
void call_once(std::once_flag& flag, Callable&& f, Args&&... args);
  • std::once_flag:一个标记对象,用于记录操作是否已经执行过。

  • Callable&& f:需要执行的可调用对象(如函数、lambda 表达式、函数对象等)。

  • Args&&... args:传递给可调用对象的参数。

工作原理

  1. 首次调用:如果 std::once_flag 标记的操作尚未执行,则 std::call_once 会调用 f,并设置 flag 标记为“已执行”。

  2. 后续调用:如果 flag 已标记为“已执行”,则后续调用 std::call_once 的线程会直接跳过 f 的执行。

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;std::once_flag flag;
void init(int id) {cout << "Initialization function called once." << endl;cout << "thread " << id << " is running." << endl;
}void worker(int id) {call_once(flag, init,id);  // 确保 init 只被调用一次
}int main() {thread t1(worker, 1);thread t2(worker, 2);thread t3(worker, 3);t1.join();t2.join();t3.join();return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com