c++11 线程支持库----互斥

本文介绍了C++11线程支持库中的互斥锁,包括std::mutex和std::timed_mutex。内容涵盖lock、try_lock、unlock等方法的使用及其注意事项,以及带超时功能的try_lock_for和try_lock_until方法。

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

互斥:   #include<mutex>     mutex:提供基本互斥设施 

std::mutex

互斥算法避免多个线程同时访问共享资源。这会避免数据竞争,并提供线程间的同步支持。

mutex 类是能用于保护共享数据免受从多个线程同时访问的同步原语。

mutex 提供排他性非递归所有权语义:

  • 调用方线程从它成功调用 lock 或 try_lock 开始,到它调用 unlock 为止占有 mutex 。
  • 线程占有 mutex 时,所有其他线程若试图要求 mutex 的所有权,则将阻塞(对于 lock 的调用)或收到 false 返回值(对于 try_lock ).
  • 调用方线程在调用 lock 或 try_lock 前必须不占有 mutex 。

若 mutex 在仍为任何线程所占有时即被销毁,或在占有 mutex 时线程终止,则行为未定义。 mutex 类满足互斥 (Mutex) 和标准布局类型 (StandardLayoutType) 的全部要求。

std::mutex 既不可复制亦不可移动。

//此示例展示 mutex 能如何用于在保护共享于二个线程间的 std::map 。
#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;

void save_page(const std::string &url)
{
	// 模拟长页面读取
	std::this_thread::sleep_for(std::chrono::seconds(2));
	std::string result = "fake content";

	std::lock_guard<std::mutex> guard(g_pages_mutex);
	g_pages[url] = result;
}

int main()
{
	std::thread t1(save_page, "http://foo");
	std::thread t2(save_page, "http://bar");
	t1.join();
	t2.join();

	// 现在不用锁访问 g_pages 是安全的,因为线程已结合
	for (const auto &pair : g_pages) {
		std::cout << pair.first << " => " << pair.second << '\n';
	}
}

std::mutex::lock

void lock();

锁定互斥。若另一线程已锁定互斥,则到 lock 的调用将阻塞执行,直至获得锁。

若 lock 为已占有 mutex 的线程调用,则行为未定义:例如,程序可能死锁。鼓励能检测非法使用的实现抛出以 resource_deadlock_would_occur 为错误条件的 std::system_error ,而不是死锁。

同一互斥上先前的 unlock() 操作同步于(定义于 std::memory_order )此操作。

注意

通常不直接调用 lock() :用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
 
//此示例演示 lock 与 unlock 能如何用于保护共享数据。
int g_num = 0;  // 为 g_num_mutex 所保护
std::mutex g_num_mutex;
 
void slow_increment(int id) 
{
    for (int i = 0; i < 3; ++i) {
        g_num_mutex.lock();
        ++g_num;
        std::cout << id << " => " << g_num << '\n';
        g_num_mutex.unlock();
 
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}
 
int main()
{
    std::thread t1(slow_increment, 0);
    std::thread t2(slow_increment, 1);
    t1.join();
    t2.join();
}

//可能输出
0 => 1
1 => 2
0 => 3
1 => 4
0 => 5
1 => 6

std::mutex::try_lock

bool try_lock();

尝试锁定互斥。立即返回。成功获得锁时返回 true ,否则返回 false 。

允许此函数虚假地失败而返回 false ,即使互斥当前未为任何其他线程所锁定。

若已占有 mutex 的线程调用 try_lock ,则行为未定义。

若此操作返回 true ,则同一互斥上的先前 unlock() 操作同步于(定义于 std::memory_order )它。注意若此操作返回 false ,则先前的 lock() 不与之同步。

#include <chrono>
#include <mutex>
#include <thread>
#include <iostream> // std::cout
 
std::chrono::milliseconds interval(100);
 
std::mutex mutex;
int job_shared = 0; // 两个线程都能修改 'job_shared',
    // mutex 将保护此变量
 
int job_exclusive = 0; // 只有一个线程能修改 'job_exclusive'
    // 不需要保护
 
// 此线程能修改 'job_shared' 和 'job_exclusive'
void job_1() 
{
    std::this_thread::sleep_for(interval); // 令 'job_2' 持锁
 
    while (true) {
        // 尝试锁定 mutex 以修改 'job_shared'
        if (mutex.try_lock()) {
            std::cout << "job shared (" << job_shared << ")\n";
            mutex.unlock();
            return;
        } else {
            // 不能获取锁以修改 'job_shared'
            // 但有其他工作可做
            ++job_exclusive;
            std::cout << "job exclusive (" << job_exclusive << ")\n";
            std::this_thread::sleep_for(interval);
        }
    }
}
 
// 此线程只能修改 'job_shared'
void job_2() 
{
    mutex.lock();
    std::this_thread::sleep_for(5 * interval);
    ++job_shared;
    mutex.unlock();
}
 
int main() 
{
    std::thread thread_1(job_1);
    std::thread thread_2(job_2);
 
    thread_1.join();
    thread_2.join();
}

std::mutex::unlock

void unlock();

解锁互斥。

互斥必须为当前执行线程所锁定,否则行为未定义。

此操作同步于(定义于 std::memory_order )任何后继的取得同一互斥所有权的锁操作。

注意

通常不直接调用 unlock() :用 std::unique_lock 与 std::lock_guard 管理排他性锁定。

实例见 void lock();  //二者总是配对使用

 

std::timed_mutex

timed_mutex 类是能用于保护数据免受多个线程同时访问的同步原语。

以类似 mutex 的行为, timed_mutex 提供排他性非递归所有权语义。另外, timed_mutex 提供通过 try_lock_for() 和 try_lock_until() 方法试图带时限地要求 timed_mutex 所有权的能力。

timed_mutex 类满足定时互斥 (TimedMutex) 与标准布局类型 (StandardLayoutType) 的所有要求。

lock() 、timed_lock()、unclock()和上面mutex相似

std::timed_mutex::try_lock_for

template< class Rep, class Period >
bool try_lock_for( const std::chrono::duration<Rep,Period>& timeout_duration );

尝试锁互斥。阻塞直到经过指定的 timeout_duration 或得到锁,取决于何者先到来。成功获得锁时返回 true , 否则返回 false 。

若 timeout_duration 小于或等于 timeout_duration.zero() ,则函数表现同 try_lock() 。

由于调度或资源争议延迟,此函数可能阻塞长于 timeout_duration 。

标准推荐用 steady_clock 度量时长。若实现用 system_clock 代替,则等待时间亦可能对时钟调整敏感。

同 try_lock() ,允许此函数虚假地失败并返回 false ,即使在 timeout_duration 中某点互斥不为任何线程所锁定。

若此操作返回 true ,则同一互斥上先前的 unlock() 调用同步于(定义于 std::memory_order )它。

若已占有 mutex 的线程调用 try_lock_for ,则行为未定义。

参数

timeout_duration-要阻塞的最大时长

返回值

若成功获得锁则为 true ,否则为 false 。

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <sstream>

std::mutex cout_mutex; // 控制到 std::cout 的访问
std::timed_mutex mutex;

void job(int id)
{
	using Ms = std::chrono::milliseconds;
	std::ostringstream stream;

	for (int i = 0; i < 3; ++i) {
		if (mutex.try_lock_for(Ms(100))) {    //要阻塞的时长
			stream << "success ";
			std::this_thread::sleep_for(Ms(100));
			mutex.unlock();
		}
		else {
			stream << "failed ";
		}
		std::this_thread::sleep_for(Ms(100));
	}

	std::lock_guard<std::mutex> lock(cout_mutex);
	std::cout << "[" << id << "] " << stream.str() << "\n";
}

int main()
{
	std::vector<std::thread> threads;
	for (int i = 0; i < 4; ++i) {
		threads.emplace_back(job, i);
	}

	for (auto& i : threads) {
		i.join();
	}
}

//可能的输出:

[0] failed failed failed 
[3] failed failed success 
[2] failed success failed 
[1] success failed success

std::timed_mutex::try_lock_until

template< class Clock, class Duration >
bool try_lock_until( const std::chrono::time_point<Clock,Duration>& timeout_time );

尝试所互斥。阻塞直至抵达指定的 timeout_time 或得到锁,取决于何者先到来。成功获得锁时返回 true ,否则返回 false 。

若已经过 timeout_time ,则此函数表现同 try_lock() 。

使用倾向于 timeout_time 的时钟,这表示时钟调节有影响。从而阻塞的最大时长可能小于但不会大于在调用时的 timeout_time - Clock::now() ,依赖于调整的方向。由于调度或资源争议延迟,函数亦可能阻塞长于抵达 timeout_time 之后。

同 try_lock() ,允许此函数虚假地失败并返回 false ,即使在 timeout_time 前的某点任何线程都不锁定互斥。

若此操作返回 true ,则同一互斥上先前的 unlock() 调用同步于(定义于 std::memory_order )它。

若已占有 mutex 的线程调用 try_lock_until ,则行为未定义。

参数

timeout_time-要阻塞到的最大时间点

返回值

若成功获得锁则为 true ,否则为 false 。

//此示例展示 10 秒的阻塞

#include <thread>
#include <iostream>
#include <chrono>
#include <mutex>

std::timed_mutex test_mutex;

void ff()
{
	auto now = std::chrono::steady_clock::now();
	test_mutex.try_lock_until(now + std::chrono::seconds(10));
	std::cout << "hello world\n";
}

int main()
{
	std::lock_guard<std::timed_mutex> l(test_mutex);
	std::thread t(ff);
	t.join();
}

//10s后输出:hello world

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值