当多个进程因为竞争共享资源而发生互相等待,导致进程无法继续执行的状态称为死锁。其中一个进程持有一个或多个资源并等待其他进程释放这些资源,而其他进程也在等待其他进程释放另一些资源,我们就说发生了死锁。
在操作系统中,死锁非常常见,因为操作系统必须大量地管理各种资源,如文件、内存、CPU时间等,这些资源可能被多个进程共享。当多个进程都需要相同的资源时,它们可能会等待对方释放资源,从而形成死锁。
死锁的发生通常有以下四个条件:
-
互斥条件:一次只能有一个进程访问资源。
-
持有和等待条件:进程已经持有一个资源,但又想要获取其他资源。
-
非抢占条件:资源不能被操作系统强制性地从进程中获取。
-
环路等待条件:一组进程互相等待对方释放资源,从而形成一个环路。
那么,如何避免死锁的发生呢?通常有以下几种方法:
-
破坏互斥条件:将一些资源变为共享资源,多个进程可以同时访问。
-
破坏持有和等待条件:要求所有进程在开始执行之前都获得它们需要的所有资源。
-
破坏非抢占条件:如果一个进程无法获得它需要的所有资源,那么它必须释放已经持有的资源。
-
破坏环路等待条件:规定所有进程必须按照相同的顺序请求资源。
下面是两个代码示例来演示死锁的发生:
示例1:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;
void* thread1(void* arg) {
pthread_mutex_lock(&mutex1);
printf("Thread 1: holding mutex 1\n");
sleep(1);
printf("Thread 1: trying to get mutex 2\n");
pthread_mutex_lock(&mutex2);
printf("Thread 1: got mutex 2\n");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
return NULL;
}
void* thread2(void* arg) {
pthread_mutex_lock(&mutex2);
printf("Thread 2: holding mutex 2\n");
sleep(1);
printf("Thread 2: trying to get mutex 1\n");
pthread_mutex_lock(&mutex1);
printf("Thread 2: got mutex 1\n");
pthread_mutex_unlock(&mutex1);
pthread_mutex_unlock(&mutex2);
return NULL;
}
int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}
上述代码创建了两个线程并分别获取了两个互斥锁,但是它们获取锁的顺序不一样,其中一个线程获取了一个锁后等待另一个锁,而另一个线程则相反。这种情况就可能发生死锁。
示例2:
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
sem_t sem1, sem2;
void* thread1(void* arg) {
sem_wait(&sem1);
printf("Thread 1: holding semaphore 1\n");
sleep(1);
printf("Thread 1: waiting for semaphore 2\n");
sem_wait(&sem2);
printf("Thread 1: got semaphore 2\n");
sem_post(&sem2);
sem_post(&sem1);
return NULL;
}
void* thread2(void* arg) {
sem_wait(&sem2);
printf("Thread 2: holding semaphore 2\n");
sleep(1);
printf("Thread 2: waiting for semaphore 1\n");
sem_wait(&sem1);
printf("Thread 2: got semaphore 1\n");
sem_post(&sem1);
sem_post(&sem2);
return NULL;
}
int main() {
sem_init(&sem1, 0, 1);
sem_init(&sem2, 0, 1);
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
}
上述代码创建了两个线程并分别获取了两个信号量,同样是获取锁的顺序不一样,其中一个线程获取了一个信号量后等待另一个信号量,而另一个线程则相反。这种情况同样也可能发生死锁。
因此,我们必须小心地在编写并发程序时避免死锁的发生。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:操作系统的死锁是什么? - Python技术站