C++11中std::mutex的使用

本文介绍了C++11标准中新增的互斥量<mutex>头文件,详细阐述了std::mutex、std::timed_mutex、std::recursive_mutex及std::recursive_timed_mutex四种互斥类的基本概念、成员函数以及使用方法,并通过示例代码展示了如何利用这些互斥量进行线程间的同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++11中新增了<mutex>,它是C++标准程序库中的一个头文件,定义了C++11标准中的一些互斥访问的类与方法等。其中std::mutex就是lock、unlock。std::lock_guard与std::mutex配合使用,把锁放到lock_guard中时,mutex自动上锁,lock_guard析构时,同时把mutex解锁。mutex又称互斥量。

C++11标准库定义了4个互斥类:

(1)、std::mutex:该类表示普通的互斥锁, 不能递归使用。

(2)、std::timed_mutex:该类表示定时互斥锁,不能递归使用。std::time_mutex比std::mutex多了两个成员函数:

A、try_lock_for():函数参数表示一个时间范围,在这一段时间范围之内线程如果没有获得锁则保持阻塞;如果在此期间其他线程释放了锁,则该线程可获得该互斥锁;如果超时(指定时间范围内没有获得锁),则函数调用返回false。

B、try_lock_until():函数参数表示一个时刻,在这一时刻之前线程如果没有获得锁则保持阻塞;如果在此时刻前其他线程释放了锁,则该线程可获得该互斥锁;如果超过指定时刻没有获得锁,则函数调用返回false。

(3)、std::recursive_mutex:该类表示递归互斥锁。递归互斥锁可以被同一个线程多次加锁,以获得对互斥锁对象的多层所有权。例如,同一个线程多个函数访问临界区时都可以各自加锁,执行后各自解锁。std::recursive_mutex释放互斥量时需要调用与该锁层次深度相同次数的unlock(),即lock()次数和unlock()次数相同。可见,线程申请递归互斥锁时,如果该递归互斥锁已经被当前调用线程锁住,则不会产生死锁。此外,std::recursive_mutex的功能与 std::mutex大致相同。

(4)、std::recursive_timed_mutex:带定时的递归互斥锁。

互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。

用于互斥锁的RAII的类模板:更好的办法是采用”资源分配时初始化”(RAII)方法来加锁、解锁,这避免了在临界区中因为抛出异常或return等操作导致没有解锁就退出的问题。极大地简化了程序员编写Mutex相关的异常处理代码。C++11的标准库中提供了std::lock_guard类模板做mutex的RAII。

std::mutex类是一个同步原语,可用于保护共享数据被同时由多个线程访问。std::mutex提供独特的,非递归的所有权语义。

        std::mutex是C++11中最基本的互斥量,std::mutex对象提供了独占所有权的特性,不支持递归地对std::mutex对象上锁。

        std::mutex成员函数:

        (1)、构造函数:std::mutex不支持copy和move操作,最初的std::mutex对象是处于unlocked状态。

        (2)、lock函数:互斥锁被锁定。线程申请该互斥锁,如果未能获得该互斥锁,则调用线程将阻塞(block)在该互斥锁上;如果成功获得该互诉锁,该线程一直拥有该互斥锁直到调用unlock解锁;如果该互斥锁已经被当前调用线程锁住,则产生死锁(deadlock)。

        (3)、unlock函数:解锁,释放调用线程对该互斥锁的所有权。

        (4)、try_lock:尝试锁定互斥锁。如果互斥锁被其他线程占有,则当前调用线程也不会被阻塞,而是由该函数调用返回false;如果该互斥锁已经被当前调用线程锁住,则会产生死锁。其中std::mutex就是lock、unlock。std::lock_guard与std::mutex配合使用,把锁放到lock_guard中时,mutex自动上锁,lock_guard析构时,同时把mutex解锁。

         (5)、native_handle:返回当前句柄。

         std::mutex: A mutex is a lockable object that is designed to signal when critical sections of code need exclusive access, preventing other threads with the same protection from executing concurrently and access the same memory locations. std::mutex objects provide exclusive ownership and do not support recursivity (i.e., a thread shall not lock a mutex it already owns).

下面是从其文章中copy的std::mutex测试代码,详细内容介绍可以参考对应的reference:

#include "mutex.hpp"
#include <iostream>
#include <mutex>
#include <thread>

namespace mutex_ {

///////////////////////////////////////////////////////////
// refrence: http://www.cplusplus.com/reference/mutex/mutex/
std::mutex mtx;           // mutex for critical section

static void print_block(int n, char c)
{
	// critical section (exclusive access to std::cout signaled by locking mtx):
	mtx.lock();
	for (int i = 0; i<n; ++i) { std::cout << c; }
	std::cout << '\n';
	mtx.unlock();
}

int test_mutex_1()
{
	std::thread th1(print_block, 50, '*');
	std::thread th2(print_block, 50, '$');

	th1.join();
	th2.join();

	return 0;
}

//////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/mutex/mutex/lock/
static void print_thread_id(int id)
{
	// std::mutex::lock: The calling thread locks the mutex
	// std::mutex::unlock: Unlocks the mutex, releasing ownership over it.
	// critical section (exclusive access to std::cout signaled by locking mtx):
	mtx.lock();
	std::cout << "thread #" << id << '\n';
	mtx.unlock();
}

int test_mutex_2()
{
	std::thread threads[10];
	// spawn 10 threads:
	for (int i = 0; i<10; ++i)
		threads[i] = std::thread(print_thread_id, i + 1);

	for (auto& th : threads) th.join();

	return 0;
}

/////////////////////////////////////////////////////////////////
// reference: http://www.cplusplus.com/reference/mutex/mutex/try_lock/
volatile int counter(0); // non-atomic counter

static void attempt_10k_increases()
{
	// std::mutex::try_lock: Lock mutex if not locked,
	// true if the function succeeds in locking the mutex for the thread, false otherwise.
	for (int i = 0; i<10000; ++i) {
		if (mtx.try_lock()) {   // only increase if currently not locked:
			++counter;
			mtx.unlock();
		}
	}
}

int test_mutex_3()
{
	std::thread threads[10];
	// spawn 10 threads:
	for (int i = 0; i<10; ++i)
		threads[i] = std::thread(attempt_10k_increases);

	for (auto& th : threads) th.join();
	std::cout << counter << " successful increases of the counter.\n";

	return 0;
}

} // namespace mutex_

GitHubhttps://github.com/fengbingchun/Messy_Test

<think>好的,我现在需要回答用户关于C++中static std::mutex的定义和用法的问题。首先,我要回忆一下std::mutex的基本概念。std::mutexC++标准库中用于多线程同步的互斥量,用于保护共享资源不被同时访问。用户提到的是static std::mutex,这意味着这个互斥量是静态的,可能属于某个类或函数内的静态成员。 接下来,我需要确认static std::mutex的定义方式。根据C++的规则,静态成员变量需要在类外进行定义和初始化。例如,在类内部声明为static std::mutex mtx;,然后在类外部定义std::mutex ClassName::mtx;。同时,C++17引入了内联变量的支持,允许在声明时直接初始化,这可能简化代码。 然后,关于用法,静态互斥量通常用于保护类的静态成员或全局共享资源。比如在多线程环境中,多个线程访问某个静态变量时,需要用互斥量进行同步。例如,在单例模式中,双重检查锁定可能会用到静态互斥量来确保线程安全。 还要注意,使用std::mutex时需要包含<mutex>头文件,并且C++11及以上版本支持。此外,互斥量的锁定和解锁通常通过RAII机制管理,比如std::lock_guard或std::unique_lock,以避免忘记解锁导致的死锁问题。 用户提供的引用中提到,std::mutex是独占互斥量,不能递归使用,所以需要确保同一线程内不会重复加锁。另外,引用中的ComputationCache结构体可能是一个缓存类,但其中没有使用互斥量,因此如果在多线程环境中使用这个类,就需要添加互斥量来保护cached_x和cached_result的访问。例如,在compute函数中检查缓存时,需要加锁确保线程安全。 可能遇到的问题包括静态成员的初始化顺序问题,尤其是在不同的编译单元中。因此,需要确保静态互斥量在使用前已经被正确初始化。此外,静态成员的生命周期是整个程序运行期间,所以需要小心避免资源泄漏。 最后,生成相关问题时,需要考虑用户可能想进一步了解的内容,比如静态互斥量的初始化方法、线程安全的单例模式、RAII机制的应用,以及不同互斥量类型的区别等。</think>### C++中static std::mutex的定义与用法 #### 1. **定义方式** 在C++中,`static std::mutex`通常用于类内或全局作用域,以保护共享资源的线程安全访问。其定义需遵循以下规则: - **类内静态成员**:在类内声明为`static`,并在类外进行初始化(C++17前需要显式定义,C++17支持内联初始化)。 ```cpp class MyClass { public: static std::mutex mtx; // 类内声明 // ... }; // 类外定义(C++17前必需) std::mutex MyClass::mtx; ``` - **全局静态互斥量**:在函数或全局作用域中使用`static`关键字定义。 ```cpp static std::mutex global_mtx; // 全局静态互斥量 ``` #### 2. **使用场景** - **保护静态成员变量**:当多个线程需要访问类的静态成员时,需用互斥量同步。 - **单例模式**:实现线程安全的单例对象初始化。 - **全局资源共享**:如日志写入、缓存访问等。 #### 3. **具体用法示例** ```cpp #include <iostream> #include <mutex> #include <thread> class Counter { public: static int value; static std::mutex mtx; static void increment() { std::lock_guard<std::mutex> lock(mtx); // RAII自动加锁/解锁 value++; } }; int Counter::value = 0; std::mutex Counter::mtx; // 类外定义静态成员 int main() { std::thread t1([]() { for (int i = 0; i < 1000; ++i) Counter::increment(); }); std::thread t2([]() { for (int i = 0; i < 1000; ++i) Counter::increment(); }); t1.join(); t2.join(); std::cout << "Final value: " << Counter::value << std::endl; // 输出2000 return 0; } ``` 此示例中,`std::lock_guard`通过RAII机制确保互斥量的自动释放,避免死锁[^2]。 #### 4. **注意事项** - **初始化顺序**:静态互斥量的初始化可能受编译单元影响,需确保在使用前已构造。 - **递归锁定**:`std::mutex`不可递归锁定,如需递归特性,改用`std::recursive_mutex`[^2]。 - **超时控制**:若需超时功能,可选用`std::timed_mutex`。 #### 5. **结合用户提供的代码** 参考用户提供的`ComputationCache`结构体[^3],若需线程安全,可修改为: ```cpp struct ComputationCache { static std::mutex mtx; // 添加静态互斥量 double cached_x = 0.0; double cached_result = 0.0; double compute(double x) { std::lock_guard<std::mutex> lock(mtx); if (cached_x != x) { cached_x = x; cached_result = /* 复杂计算 */; } return cached_result; } }; // 类外定义静态成员 std::mutex ComputationCache::mtx; ``` --- 相关问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值