目录
死锁的危害
死锁出现的原因
死锁的解决方法
死锁是计算机科学中一个非常重要的概念,特别是在多线程、并发编程以及数据库管理系统等领域中。下面是关于死锁的危害、出现原因和解决方法的基础概述:
死锁的危害
- 资源浪费:死锁导致系统中的资源被无效地占用,而无法释放,从而浪费了系统资源。
- 程序停滞:死锁会导致相关进程或线程被永久阻塞,无法继续执行,从而影响系统的正常运行。
- 系统崩溃:在一些情况下,死锁可能导致系统崩溃,从而造成严重的后果。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mutex1;
std::mutex mutex2;void function1() {std::lock_guard<std::mutex> lock1(mutex1);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock2(mutex2);std::cout << "Function 1 acquired mutex1 and mutex2\n";
}void function2() {std::lock_guard<std::mutex> lock2(mutex2);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock1(mutex1);std::cout << "Function 2 acquired mutex2 and mutex1\n";
}int main() {std::thread t1(function1);std::thread t2(function2);t1.join();t2.join();return 0;
}
这段代码创建了两个线程,每个线程都试图获取两个互斥量(mutex1
和mutex2
)的所有权,但是获取的顺序是相反的。如果这两个线程同时运行,就会发生死锁,因为一个线程持有了mutex1
,但试图获取mutex2
,而另一个线程持有了mutex2
,但试图获取mutex1
,从而导致彼此互相等待,最终导致程序停滞。
为了避免死锁,需要确保在多个线程中获取互斥量的顺序是一致的。
死锁出现的原因
死锁通常发生在多个进程或线程之间,由于彼此持有对方所需的资源而导致的循环等待。常见的原因包括:
- 资源竞争:多个进程争夺有限的资源,但由于资源分配不当或者进程执行顺序不当,导致发生死锁。
- 进程推进顺序不当:当多个进程按照不同的顺序获取资源,但释放资源的顺序不当时,可能导致死锁。
- 并发访问共享资源:多个进程同时访问共享资源,并且不加控制地相互等待对方释放资源,从而导致死锁。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mutex;void access_shared_resource(int thread_id) {std::lock_guard<std::mutex> lock(mutex); // 获取互斥锁std::cout << "Thread " << thread_id << " is accessing the shared resource.\n";std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟访问共享资源需要的时间// 假设这里需要访问另一个共享资源std::lock_guard<std::mutex> lock2(mutex); // 再次获取互斥锁,尝试访问另一个共享资源std::cout << "Thread " << thread_id << " is accessing another shared resource.\n";
}int main() {std::thread t1(access_shared_resource, 1);std::thread t2(access_shared_resource, 2);t1.join();t2.join();return 0;
}
在这个例子中,两个线程 t1
和 t2
同时尝试访问共享资源,并且在获取第一个共享资源后,又尝试获取另一个共享资源。然而,它们没有适当地协调共享资源的访问顺序,而是简单地相互等待对方释放资源,这可能导致死锁。
这个例子展示了并发访问共享资源时可能发生的死锁情况,因为多个进程(或线程)同时访问共享资源,并且不加控制地相互等待对方释放资源,从而导致了死锁的发生。
死锁的解决方法
- 避免死锁:通过合理地设计算法和资源分配策略,使系统尽量避免进入死锁状态。比如,银行家算法等。
- 检测与恢复:设计算法检测系统中的死锁,并且在检测到死锁时采取相应的措施进行恢复,如中断一些进程或者回滚操作。
- 预防死锁:采用一些方法预防死锁的发生,例如破坏死锁产生的必要条件之一,比如破坏循环等待条件、破坏互斥条件等。
- 资源分配策略:采用合适的资源分配策略,确保资源的有效利用,并且尽量减少死锁的发生。
#include <iostream>
#include <thread>
#include <mutex>std::mutex mutex1;
std::mutex mutex2;void function1() {std::lock(mutex1, mutex2); // 使用 std::lock 来一次性获取多个互斥量的所有权,避免死锁std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock); // 使用 std::adopt_lock 参数表示已经拥有互斥量的所有权std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);std::cout << "Function 1 acquired mutex1 and mutex2\n";// 这里执行任务
}void function2() {std::lock(mutex1, mutex2); // 使用 std::lock 来一次性获取多个互斥量的所有权,避免死锁std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock); // 使用 std::adopt_lock 参数表示已经拥有互斥量的所有权std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);std::cout << "Function 2 acquired mutex1 and mutex2\n";// 这里执行任务
}int main() {std::thread t1(function1);std::thread t2(function2);t1.join();t2.join();return 0;
}
在这个例子中,function1
和 function2
都试图获取 mutex1
和 mutex2
的所有权。通过使用 std::lock
函数一次性获取多个互斥量的所有权,并且使用 std::adopt_lock
参数表示已经拥有互斥量的所有权,可以避免死锁的发生。这种方式可以保证无论线程以什么顺序获取锁,都不会发生死锁。
这些方法通常是根据具体情况和需求来选择和应用的,不能一概而论。在实际应用中,通常需要根据系统的特点和需求综合考虑,选择合适的死锁处理方法。