产生死锁的原因:
- 因为系统资源不足
- 进程运行推进的顺序不合适
- 资源分配不当等
如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的条件:
- 互斥:一个资源每次只能被一个进程使用
- 占有且等待:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 非抢占:进程已获得的资源,在末使用完之前,不能强行抢占
- 循环等待:存在一个封闭的进程链,使得每个资源至少占有此链中下一个进程所需要的一个资源
死锁的预防:
间接的死锁预防:防止前三个必要条件中的任何一个发生
1.就是在系统里取消互斥。若资源不被一个进程独占使用,那么死锁是肯定不会发生的。但一般来说在所列的四个条件中,”互斥”条件是无法破坏的。因此,在死锁预防里主要是破坏其他几个必要条件,而不去涉及破坏”互斥”条件。
2.破坏”占有并等待”条件,就是在系统中不允许进程在已获得某种资源的情况下,申请其他资源。即要想出一个办法,阻止进程在持有资源的同时申请其他资源。
方法一:
创建进程时,要求它申请所需的全部资源,系统或满足其所有要求,或么什么也不给它。这是所谓的 ” 一次性分配”方案。
方法二:
要求每个进程提出新的资源申请前,释放它所占有的资源。这样,一个进程在需要资源S时,须先把它先前占有的资源R释放掉,然后才能提出对S的申请,即使它可能很快又要用到资源R。
3.破坏”不可抢占”条件就是允许对资源实行抢夺。
方法一:
如果占有某些资源的一个进程进行进一步资源请求被拒绝,则该进程必须释放它最初占有的资源,如果有必要,可再次请求这些资源和另外的资源。
方法二:
如果一个进程请求当前被另一个进程占有的一个资源,则操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不相同的条件下,方法二才能预防死锁。直接的死锁预防:防止循环等待的发生
破坏”循环等待”条件的一种方法,是将系统中的所有资源统一编号,进程可在任何时刻提出资源申请,但所有申请必须按照资源的编号顺序(升序)提出。这样做就能保证系统不出现死锁。
死锁的避免:
允许三个必要条件,但通过明智的选择,确保永不会到达死锁点,因此死锁避免比死锁预防允许更多的并发,对于死锁避免的方法,是否允许当前的资源分配请求是动态决定的,这就有可能导致死锁。因此死锁避免需要知道将来的进程资源请求的情况。
例如: 如果一个进程的请求会导致死锁,则不启动此进程;如果一个进程增加资源的请求会导致死锁,则不允许此分配
同步与互斥:
mutex(互斥量)与Condition(条件变量)
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<assert.h>
#include<pthread.h>
typedef struct Node
{
int data;
struct Node* next;
}Node, *Node_p, **Node_pp;
static Node_p is_empty(Node_p _h)
{
if (NULL == _h->next)
{
return NULL;
}
return _h;
}
static Node_p alloc_node(int data)
{
Node_p _h = (Node_p)malloc(sizeof(Node));
if (NULL != _h)
{
_h->next = NULL;
_h->data = data;
}
return _h;
}
void init_node(Node_pp _h)
{
(*_h) = alloc_node(0);
}
void push(Node_pp _h, int _d)
{
assert(_h);
if (is_empty((*_h)))
{
Node_p tmp = alloc_node(_d);
tmp->next = (*_h)->next;
(*_h)->next = tmp;
}
else{
(*_h)->next = alloc_node(_d);
(*_h)->next->data = _d;
(*_h)->next->next = NULL;
}
}
void pop(Node_pp _h)
{
assert(_h);
if (is_empty((*_h)))
{
Node_p tmp = (*_h)->next;
(*_h)->next = tmp->next;
free(tmp);
}
}
void destory_node(Node_pp _h)
{
while(is_empty((*_h)))
{
pop(_h);
}
free((*_h));
*_h = NULL;
}
void Print(Node_pp _h)
{
Node_p tmp = (*_h)->next;
while (NULL != tmp)
{
printf("%d ",tmp->data);
tmp = tmp->next;
}
printf("\n");
}
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER ;
pthread_cond_destroy(pthread_cond_t *cond); pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* comsum(void *arg)
{
Node_p _h = (Node_p)arg;
for(;;)
{
pthread_mutex_lock(&mutex);
printf("comsum pop .....\n");
while(!is_empty(_h))
{
pthread_cond_wait(&cond,&mutex);
}
Print(&_h);
pop(&_h);
printf("end pop....\n");
pthread_mutex_unlock(&mutex);
}
}
void* product(void* arg)
{
Node_p _h = (Node_p)arg;
for(;;)
{
sleep(1);
pthread_mutex_lock(&mutex);
printf("product push ....\n");
push(&_h,rand()%123);
Print(&_h);
printf("end product...\n");
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
}
}
int main()
{
Node_p head;
init_node(&head);
pthread_t tid1;
pthread_t tid2;
pthread_create(&tid1,NULL,product,head);
pthread_create(&tid2,NULL,comsum,head);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}