网站漂浮广告代码,价格低质量好的广告语,会员网站模板,网店美工课程阅读导航 引言一、Mutex的简介二、Mutex的种类1. std::mutex #xff08;基本互斥锁#xff09;2. std::recursive_mutex #xff08;递归互斥锁#xff09;3. std::timed_mutex #xff08;限时等待互斥锁#xff09;4. std::recursive_timed_mutex #xff08;限时等待… 阅读导航 引言一、Mutex的简介二、Mutex的种类1. std::mutex 基本互斥锁2. std::recursive_mutex 递归互斥锁3. std::timed_mutex 限时等待互斥锁4. std::recursive_timed_mutex 限时等待递归互斥锁 三、总结温馨提示 引言
在多线程编程中保证数据的同步和互斥是至关重要的。而互斥锁Mutex作为一种常用的同步机制在C11标准中被引入提供了一种简单有效的方式来控制多个线程对共享资源的访问。互斥锁可以确保同一时间只有一个线程可以持有锁并且其他线程需要等待锁释放后才能继续执行从而避免了多个线程同时访问共享资源所导致的数据竞争和不一致性问题。本文将详细介绍互斥锁的种类、使用方法以及一些常见的注意事项帮助读者更好地理解和应用互斥锁来实现线程安全的程序。
一、Mutex的简介
⭕Mutex官方文档 Mutex互斥量是一种同步原语用于实现多线程环境下的资源互斥访问。它允许多个线程同时访问共享资源但在任何给定时间只能有一个线程能够获得对该资源的独占访问权。Mutex主要用于防止数据竞争和确保数据的一致性。
在C11之前开发人员通常使用操作系统提供的互斥机制来实现线程间的同步。而C11引入的Mutex则提供了一种标准化的、跨平台的解决方案使得多线程编程更加简单和可靠。
Mutex的基本操作包括锁定lock和解锁unlock。当一个线程需要访问共享资源时它会尝试对Mutex进行加锁操作如果Mutex已经被其他线程锁定那么该线程将被阻塞直到Mutex被解锁。一旦线程完成对共享资源的操作它会释放Mutex允许其他线程获得对资源的访问权。
使用Mutex可以有效地避免数据竞争和保护共享资源的一致性。然而Mutex也存在一些潜在问题如死锁deadlock和饥饿starvation。为了避免这些问题开发人员需要仔细设计和管理Mutex的使用并采用合适的同步机制。
二、Mutex的种类
⭕在C11中Mutex总共包了四个互斥量的种类分别是
Mutex类型描述std::mutex最基本的互斥锁类型用于实现线程间的互斥访问。只允许一个线程获得锁其他线程需要等待锁被释放才能继续执行。std::recursive_mutex与std::mutex类似但允许同一线程多次获取锁。也就是说同一线程可以多次对该锁进行加锁操作每次加锁都需要对应的解锁操作。std::timed_mutex可限时等待的互斥锁类型。与std::mutex类似但允许线程在尝试获取锁时设置一个超时时间。如果锁在指定的时间内无法被获得线程将不再等待并返回相应的错误代码。std::recursive_timed_mutex可限时等待的递归互斥锁类型。结合了std::recursive_mutex和std::timed_mutex的特性允许同一线程多次获取锁并且可以设置超时时间。
以上是四种常见的Mutex类型及其描述适用于不同的场景下面我会详细介绍这四个Mutex类型。
1. std::mutex 基本互斥锁
std::mutex是C标准库中提供的最基本的互斥锁类型之一。它用于实现线程间的互斥访问即在一个时间点只允许一个线程获得锁其他线程需要等待锁被释放才能继续执行。使用std::mutex可以保证多个线程对共享资源的访问顺序并避免数据竞争产生的问题。
注意该类的对象之间不能拷贝也不能进行移动。
⭕std::mutex最常用的三个函数是
函数名描述lock()尝试获取互斥锁。如果未被其他线程占用则当前线程获取锁否则阻塞等待锁的释放。unlock()释放互斥锁。如果当前线程持有锁则释放锁否则行为未定义。try_lock()尝试获取互斥锁不会阻塞线程。如果未被其他线程占用则当前线程获取锁并返回true否则返回false。
这三个函数组成了基本的互斥锁操作也是使用std::mutex时最常用的三个函数。其中lock()和unlock()通常需要成对使用以确保锁得到正确的管理。try_lock()则可以用于一些特殊情况下的非阻塞式加锁操作例如在轮询等待某个资源时可以尝试获取锁并立即返回结果。
注意事项
线程函数调用lock()时可能会发生以下三种情况 如果该互斥量当前没有被锁住则调用线程将该互斥量锁住直到调用 unlock之前该线程一直拥有该锁。如果当前互斥量被其他线程锁住则当前的调用线程被阻塞住。如果当前互斥量被当前调用线程锁住则会产生死锁(deadlock) 线程函数调用try_lock()时可能会发生以下三种情况 如果当前互斥量没有被其他线程占有则该线程锁住互斥量直到该线程调用 unlock释放互斥量。如果当前互斥量被其他线程锁住则当前调用线程返回 false而并不会被阻塞掉。如果当前互斥量被当前调用线程锁住则会产生死锁(deadlock)
2. std::recursive_mutex 递归互斥锁
std::recursive_mutex是C标准库中提供的一个递归互斥锁类型用于实现线程间的互斥访问。与std::mutex相比std::recursive_mutex可以允许同一线程多次获取互斥锁而不会导致死锁。简单来说就是允许同一个线程对互斥量多次上锁即递归上锁来获得对互斥量对象的多层所有权释放互斥量时需要调用与该锁层次深度相同次数的 unlock()
std::recursive_mutex定义在mutex头文件中。与std::mutex类似可以通过定义std::recursive_mutex对象来创建一个递归互斥锁。例如
#include mutex
//这里定义了一个名为mtx的std::recursive_mutex对象用于保护某个共享资源的访问。
std::recursive_mutex mtx;std::recursive_mutex的主要方法和std::mutex相同包括lock()、unlock()和try_lock()。这些方法的功能和使用方式也与std::mutex一致。区别在于当同一线程多次尝试获取std::recursive_mutex时它不会导致死锁而是允许同一线程多次获取锁需要相应次数的解锁操作才能完全释放锁。
3. std::timed_mutex 限时等待互斥锁
std::timed_mutex是C标准库中提供的一个可超时等待的互斥锁类型用于实现线程间的互斥访问。与std::mutex相比std::timed_mutex在尝试获取锁的时候可以设置超时时间避免线程由于无法获取锁而一直被阻塞等待从而提高程序的健壮性。
std::timed_mutex定义在mutex头文件中。与std::mutex类似可以通过定义std::timed_mutex对象来创建一个可超时等待的互斥锁。例如
#include mutex
//这里定义了一个名为mtx的std::timed_mutex对象用于保护某个共享资源的访问。
std::timed_mutex mtx;std::timed_mutex的主要方法和std::mutex相同包括lock()、unlock()和try_lock()。不同的是std::timed_mutex提供了try_lock_for()和try_lock_until()这两个方法用于在指定的时间范围内尝试获取互斥锁。
try_lock_for()方法允许线程尝试在指定的时间段内获取互斥锁如果在指定时间内无法获取锁则返回false。例如
std::timed_mutex mtx;
std::chrono::milliseconds timeout(100);if (mtx.try_lock_for(timeout))
{// 成功获取锁// ...mtx.unlock(); // 释放锁
}
else
{// 超时等待未能获取锁// ...
}try_lock_until()方法允许线程尝试在指定的时间点之前获取互斥锁如果在指定时间点之前无法获取锁则返回false。例如
std::timed_mutex mtx;
std::chrono::system_clock::time_point deadline std::chrono::system_clock::now() std::chrono::milliseconds(100);if (mtx.try_lock_until(deadline))
{// 成功获取锁// ...mtx.unlock(); // 释放锁
}
else
{// 超时等待未能获取锁// ...
}4. std::recursive_timed_mutex 限时等待递归互斥锁
std::recursive_timed_mutex是C11标准库中提供的一个可递归、可超时等待的互斥锁类型它是std::timed_mutex的另一个版本。与std::timed_mutex一样std::recursive_timed_mutex用于实现线程间的互斥访问但它允许同一线程多次获取锁从而避免死锁等问题。
std::recursive_timed_mutex定义在mutex头文件中。和std::timed_mutex类似可以通过定义std::recursive_timed_mutex对象来创建一个可递归、可超时等待的互斥锁。例如
#include mutex
//这里定义了一个名为mtx的std::recursive_timed_mutex对象用于保护某个共享资源的访问。
std::recursive_timed_mutex mtx;std::recursive_timed_mutex的主要方法和std::timed_mutex相同包括lock()、unlock()和try_lock()。不同的是std::recursive_timed_mutex允许同一线程多次获取锁从而避免死锁等问题。例如
void foo()
{std::unique_lockstd::recursive_timed_mutex lock(mtx);// ...bar(); // 调用另一个函数// ...
}void bar()
{std::unique_lockstd::recursive_timed_mutex lock(mtx); // 可以再次获取锁// ...
}在上面的例子中foo()函数和bar()函数都使用了std::unique_lock对象来获取mtx互斥锁。由于std::recursive_timed_mutex允许同一线程多次获取锁因此bar()函数可以再次获取锁而不会导致死锁等问题。
与std::timed_mutex类似std::recursive_timed_mutex也提供了try_lock_for()和try_lock_until()方法用于在指定的时间范围内尝试获取锁。例如
std::recursive_timed_mutex mtx;
std::chrono::milliseconds timeout(100);if (mtx.try_lock_for(timeout))
{// 成功获取锁// ...mtx.unlock(); // 释放锁
}
else
{// 超时等待未能获取锁// ...
}注意由于std::recursive_timed_mutex允许同一线程多次获取锁因此在释放锁之前必须将锁计数器减少到零。否则其他线程将无法获取到锁从而导致死锁等问题。
三、总结
在使用互斥锁时需要注意正确地加锁和解锁以避免资源竞争和死锁等问题的发生。在大多数情况下应优先选择最简单的互斥锁类型std::mutex只有在需要递归、限时等待功能时才考虑其他类型。选择互斥锁类型应根据具体需求和场景来进行。
通过合理使用互斥锁可以保证多线程程序的正确性和稳定性提高多线程程序的性能和并发能力。
温馨提示
感谢您对博主文章的关注与支持另外我计划在未来的更新中持续探讨与本文相关的内容会为您带来更多关于C以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新不要错过任何精彩内容
再次感谢您的支持和关注。期待与您建立更紧密的互动共同探索C、算法和编程的奥秘。祝您生活愉快排便顺畅