多线程——线程互斥锁
1.前言
多线程技术是一种使计算机能够同时执行多个任务的技术。在软件开发中,多线程可以提高应用程序的响应性和计算密集型任务的性能。多应用于Web服务器和专用服务器,后台任务和异步处理,分布式计算,实时交互系统等
以下是我整理的我这几天学习到的多线程的知识。
以下代码所需要的头文件
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
2.概念
为甚莫要使用互斥锁呢,因为在多线程编程中,可能出现许多线程要使用**同一变量**,但是每个线程对这个变量的**读操作**和**写操作**是需要时间的。一个线程可能读取到另一个线程**写操作**完成之前的数据,并且和另一个线程执行了同样的操作。比如说有两个用户同时修改一段数据(读取到了同一段数据),他们同时在结尾加了一段数据(同时进行写操作),后执行完写操作的人的数据覆盖了先执行完写操作的数据,导致其中一人的数据丢失。
而想要避免上面这种情况发生,必须在对共享的数据进行写操作的时候只能由一个线程来写,等到这个线程的写操作完成后,才能轮到其他线程来执行写操作。这就要使用互斥锁。
互斥锁的作用,是使一段程序变成临界区。
在多线程编程中,临界区(Critical Section)是指每个线程中访问临界资源的那段代码。临界资源是一次仅允许一个线程使用的共享资源。临界区的主要目的是确保多个线程互斥地访问共享资源,从而避免数据竞争和不一致性。
临界资源也就是上面说的共享的数据(由多个线程去访问)。
3.代码
1.互斥锁
下面的代码展示的互斥锁std::mutex的使用方法。int count = 0; //共享变量
std::mutex mtx; //互斥锁
void thread_func(int times) {
for (int i = 0; i < times; i++) {
//竞争
mtx.lock(); //上锁
count++;
mtx.unlock(); //解锁
}
}
这里使用了c++的mutex互斥锁。当一个线程使用lock()函数上锁后,别的线程将无法上锁,只能等到上锁的线程使用unlock()函数解锁以后才能上锁。
mutex有以下几个函数
- 构造函数,mutex不能使用拷贝构造函数和移动构造函数。
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;
- lock()函数,加锁。如果别的线程已经加锁,线程会在此处阻塞。
注意!!!如果对同一个线程重复加锁可能导致死锁。 - unlock()函数,解锁。
- try_lock()函数,尝试锁住互斥量。和lock()不同的是如果别的线程已经加锁,则不会阻塞而是继续执行下去。
以下是主函数
int main() {
int times = 1000000;
std::thread t1(thread_func, times);
std::thread t2(thread_func, times);
t1.join();
t2.join();
std::cout << "count:" << count << std::endl;
return 0;
}
得出的结果是
count:2000000
2.定时互斥锁
还有另一个会用到的互斥锁是std::timed_mutex.(定时互斥锁)std::timed_mutex比mutex多了两个函数,分别为- try_lock_for()函数,传入一个时间范围,在这时间范围没有获得锁则会阻塞住。超出时间范围则会返回false。
std::timed_mutex tmtx; //定时互斥量
void thread_func2(int times) {
for (int i = 0; i < times; i++) {
//竞争
if (tmtx.try_lock_for(std::chrono::milliseconds(200))) { //上锁,尝试在200ms内获取锁
std::cout << "thread_func2:" << std::this_thread::get_id() << std::endl;
tmtx.unlock(); //解锁
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));//睡眠1秒
}
}
上述代码演示了try_lock_for()的使用方法。线程获得锁后打印线程的id。
其中std::chrono::milliseconds(200)使用了库chrono来表示 500 毫秒的时间间隔。
- try_lock_until()函数,传入一个时间点,在这时间点到来之前没有获得锁则会阻塞住。超出时间点则会返回false。
void thread_func2(int times) {
for (int i = 0; i < times; i++) {
//竞争
auto now = std::chrono::system_clock::now(); //获取当前时间
if (tmtx.try_lock_until(now + std::chrono::milliseconds(200))) { //上锁
std::cout << "thread_func2:" << std::this_thread::get_id() << std::endl;
tmtx.unlock(); //解锁
}
std::this_thread::sleep_for(std::chrono::milliseconds(1000));//睡眠1秒
}
}
上述代码演示了try_lock_until()的使用方法。线程获得锁后打印线程的id。
其中auto now = std::chrono::system_clock::now();使用库chrono来获取当前时间。
而now + std::chrono::milliseconds(200)表示在当前时间200ms后的时间点。

以上为我在学习过程中整理的知识点,如有哪里说错了感谢指出
推荐一个讲的比较好的up主的视频【32.线程同步与mutex】https://www.bilibili.com/video/BV1eZ421g7jK?vd_source=dccc0abff62c8559f0a5ed0bce39dec2

浙公网安备 33010602011771号