品牌网站建是啥意思,公司做网站需要网站维护人员吗,鄂尔多斯 网站制作,Wordpress怎么做引导页死锁#xff08;Deadlock#xff09;是指两个或两个以上的进程#xff08;或线程#xff09;在执行过程中#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象#xff0c;若无外力作用#xff0c;它们都将无法推进下去。此时称系统处于死锁状态或系统产生了…死锁Deadlock是指两个或两个以上的进程或线程在执行过程中由于竞争资源或者由于彼此通信而造成的一种阻塞的现象若无外力作用它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁这些永远在互相等待的进程或线程称为死锁进程或线程。
死锁的产生需要满足四个必要条件这四个条件被称为死锁的四个必要条件Coffman条件它们是
互斥条件一个资源每次只能被一个进程使用。请求与保持条件一个进程因请求资源而阻塞时对已获得的资源保持不放。不剥夺条件进程已获得的资源在未使用完之前不能强行剥夺。循环等待条件系统中若干进程形成一种头尾相接的循环等待资源关系。
如果上述四个条件同时成立系统就可能发生死锁。
操作系统层面的死锁最早在1965年由Dijkstra在研究银行家算法时提出它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。死锁的恢复和预防是操作系统的重要设计目标之一常见的死锁预防和恢复策略包括鸵鸟算法系统假装没有死锁发生和死锁检测和恢复系统并不试图阻止死锁的产生而是允许死锁发生当检测到死锁发生后采取措施进行恢复。
1.线程死锁
本节基于线程去讲解死锁。
有时一个线程需要同时访问两个或更多不同的共享资源而每个资源又都由不同的互斥量管理。当超过一个线程加锁同一组互斥量时就有可能发生死锁。
两个或两个以上的进程在执行过程中因争夺共享资源而造成的一种互相等待的现象若无外力作用它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁 死锁的几种场景1忘记释放锁2重复加锁3多线程多锁抢占锁资源 2连续两次或多次调用 pthread_mutex_lock 来锁定同一个互斥量mutex而没有相应的 pthread_mutex_unlock 调用会导致死锁deadlock。这是因为互斥量的设计初衷是确保同一时间只有一个线程可以访问被保护的资源或代码段。 当你第一次调用 pthread_mutex_lock(mutex); 时如果互斥量 mutex 已经被其他线程锁定当前线程将会阻塞直到互斥量被解锁。如果当前线程已经拥有了这个互斥量即它之前已经成功锁定了这个互斥量但还没有解锁那么再次调用 pthread_mutex_lock(mutex); 会导致线程阻塞因为它在等待自己释放互斥量这是一个逻辑错误。 测试代码
#include stdio.h
#include pthread.h
#include unistd.h// 创建2个互斥量
pthread_mutex_t mutex1, mutex2;void * workA(void * arg) {pthread_mutex_lock(mutex1);sleep(1);pthread_mutex_lock(mutex2);printf(workA....\n);pthread_mutex_unlock(mutex2);pthread_mutex_unlock(mutex1);return NULL;
}void * workB(void * arg) {pthread_mutex_lock(mutex2);sleep(1);pthread_mutex_lock(mutex1);printf(workB....\n);pthread_mutex_unlock(mutex1);pthread_mutex_unlock(mutex2);return NULL;
}int main() {// 初始化互斥量pthread_mutex_init(mutex1, NULL);pthread_mutex_init(mutex2, NULL);// 创建2个子线程pthread_t tid1, tid2;pthread_create(tid1, NULL, workA, NULL);pthread_create(tid2, NULL, workB, NULL);// 回收子线程资源pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 释放互斥量资源pthread_mutex_destroy(mutex1);pthread_mutex_destroy(mutex2);return 0;
} 上述代码最终执行不会输出任何东西。 首先workA对1加锁然后睡眠1秒。这个时候可能轮到B执行了B先对2进行加锁然后睡眠1秒。此时A醒了尝试对2进行加锁而2已经被B加锁了因此A阻塞。轮到B的时候对1进行加锁然后1已经被A加上了所以B阻塞等待。所有发生了死锁。 2.读写锁 当有一个线程已经持有互斥锁时互斥锁将所有试图进入临界区的线程都阻塞住。但是考虑一种情形当前持有互斥锁的线程只是要读访问共享资源而同时有其它几个线程也想读取这个共享资源但是由于互斥锁的排它性所有其它线程都无法获取锁也就无法读访问共享资源了但是实际上多个线程同时读访问共享资源并不会导致问题。 在对数据的读写操作中更多的是读操作写操作较少例如对数据库数据的读写应用。 为了满足当前能够允许多个读出但只允许一个写入的需求线程提供了读写锁来实现。 ◼ 读写锁的特点 如果有其它线程读数据则允许其它线程执行读操作但不允许写操作。 如果有其它线程写数据则其它线程都不允许读、写操作。 写是独占的写的优先级高。 如果A线程加的是读锁然后B线程是要加写锁C线程是要加读锁。那么由于写的优先级高因此B先加写锁。 测试代码
/*读写锁的类型 pthread_rwlock_tint pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);案例8个线程操作同一个全局变量。3个线程不定时写这个全局变量5个线程不定时的读这个全局变量
*/#include stdio.h
#include pthread.h
#include unistd.h// 创建一个共享数据,作为全局变量
int num 1;// pthread_mutex_t mutex;互斥锁的效率相比于读写锁要慢
//创建读写锁
pthread_rwlock_t rwlock;void * writeNum(void * arg) {while(1) {pthread_rwlock_wrlock(rwlock);num;printf(write, tid : %ld, num : %d\n, pthread_self(), num);pthread_rwlock_unlock(rwlock);usleep(100);}return NULL;
}void * readNum(void * arg) {while(1) {pthread_rwlock_rdlock(rwlock);printf(read, tid : %ld, num : %d\n, pthread_self(), num);pthread_rwlock_unlock(rwlock);usleep(100);}return NULL;
}int main() {pthread_rwlock_init(rwlock, NULL);// 创建3个写线程5个读线程pthread_t wtids[3], rtids[5];for(int i 0; i 3; i) {pthread_create(wtids[i], NULL, writeNum, NULL);}for(int i 0; i 5; i) {pthread_create(rtids[i], NULL, readNum, NULL);}// 设置线程分离for(int i 0; i 3; i) {pthread_detach(wtids[i]);}for(int i 0; i 5; i) {pthread_detach(rtids[i]);}pthread_exit(NULL);pthread_rwlock_destroy(rwlock);return 0;
} 最后三行代码的原因是如果destory在先因为上面的detach运行后子线程可能没有运行完所以可能会在子线程运行过程中destory互斥量这样会出错如果destory在后那么主线程exit后也不会去destory互斥量所以我建议上面回收子线程使用join因为join是阻塞的会等所有的子进程资源回收完了再继续然后再destory互斥量最后exit主线程。 也就是说用pthread_join最后最初主线程pthread_exit(NULL)