pthread条件变量和mutex,程序出现死锁
pthread condition variables and mutex, program has a deadlock
我的多线程代码有问题,有一个死锁,但我不知道如何修复它,因为我是 pthreads 的新手。
下面的代码显示了一个名为 "idle" 的函数,它正在等待一个模拟进程被放置在就绪队列中,推送函数应该将该进程放置在队列中,然后发出信号表明有一个进程已准备好安排。
下面是导致死锁的两个函数:
void push(pcb_t *pcb) {
pthread_mutex_lock(&queue_mutex);
if (head == NULL) {
head = pcb;
tail = pcb;
} else {
pcb_t *old_tail = tail;
tail = pcb;
old_tail->next = tail;
}
pthread_cond_signal(&proc_ready);
pthread_mutex_unlock(&queue_mutex);
}
extern void idle(unsigned int cpu_id)
{
pthread_mutex_lock(&queue_mutex);
while(head == NULL) {
pthread_cond_wait(&proc_ready, &queue_mutex);
}
pthread_mutex_unlock(&queue_mutex);
schedule(cpu_id);
/*
* idle() must block when the ready queue is empty, or else the CPU threads
* will spin in a loop. Until a ready queue is implemented, we'll put the
* thread to sleep to keep it from consuming 100% of the CPU time. Once
* you implement a proper idle() function using a condition variable,
* remove the call to mt_safe_usleep() below.
*/
}
这是 gdb 回溯:
Thread 2 (Thread 0xb7df7b40 (LWP 3443)):
#0 0xb7fdd424 in __kernel_vsyscall ()
No symbol table info available.
#1 0xb7fb59e2 in __lll_lock_wait ()
at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:144
No locals.
#2 0xb7fb1267 in _L_lock_847 () from /lib/i386-linux-gnu/libpthread.so.0
No symbol table info available.
#3 0xb7fb10a0 in __GI___pthread_mutex_lock (mutex=0x804c75c <queue_mutex>)
at ../nptl/pthread_mutex_lock.c:79
__PRETTY_FUNCTION__ = "__pthread_mutex_lock"
type = 0
id = <optimized out>
#4 0x080489d9 in idle (cpu_id=0) at student.c:116
No locals.
#5 0x08048f65 in simulator_cpu_thread (cpu_id=0) at os-sim.c:259
state = CPU_IDLE
#6 0x08049b4a in simulator_cpu_thread_func (data=0x0) at os-sim.c:618
No locals.
#7 0xb7faef70 in start_thread (arg=0xb7df7b40) at pthread_create.c:312
__res = <optimized out>
pd = 0xb7df7b40
now = <optimized out>
unwind_buf = {cancel_jmp_buf = {{jmp_buf = {-1208217600, -1210090688, 4001536,
-1210092504, -193645269, -1085428949}, mask_was_saved = 0}}, priv = {
pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0,
canceltype = 0}}}
not_first_call = <optimized out>
pagesize_m1 = <optimized out>
sp = <optimized out>
freesize = <optimized out>
---Type <return> to continue, or q <return> to quit---
__PRETTY_FUNCTION__ = "start_thread"
#8 0xb7ee5bee in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129
No locals.
Thread 1 (Thread 0xb7df8700 (LWP 3439)):
#0 0xb7fdd424 in __kernel_vsyscall ()
No symbol table info available.
#1 0xb7fb59e2 in __lll_lock_wait ()
at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:144
No locals.
#2 0xb7fb1267 in _L_lock_847 () from /lib/i386-linux-gnu/libpthread.so.0
No symbol table info available.
#3 0xb7fb10a0 in __GI___pthread_mutex_lock (mutex=0x804c75c <queue_mutex>)
at ../nptl/pthread_mutex_lock.c:79
__PRETTY_FUNCTION__ = "__pthread_mutex_lock"
type = 0
id = <optimized out>
#4 0x0804886f in push (pcb=0x804c660 <processes>) at student.c:42
No locals.
#5 0x08048acb in wake_up (process=0x804c660 <processes>) at student.c:205
No locals.
#6 0x08049a14 in simulate_io () at os-sim.c:590
completed = 0x804d0f8
pcb = 0x804c660 <processes>
#7 0x08048e0f in simulator_supervisor_thread () at os-sim.c:189
No locals.
#8 0x08048dcc in start_simulator (new_cpu_count=1) at os-sim.c:161
n = 1
__PRETTY_FUNCTION__ = "start_simulator"
#9 0x08048ba8 in main (argc=2, argv=0xbffff284) at student.c:240
cpu_count = 1
__PRETTY_FUNCTION__ = "main"
编辑:也使用 queue_mutex
的 pop 函数
pcb_t * pop() {
pcb_t *pcb = NULL;
pthread_mutex_lock(&queue_mutex);
if (head == NULL) {
return NULL;
} else if (head == tail) {
pcb = head;
head = NULL;
tail = NULL;
} else {
pcb = head;
head = head->next;
}
pthread_mutex_unlock(&queue_mutex);
pcb->next = NULL;
return pcb;
}
在 head == NULL 情况下,您的 pop 函数不会解锁互斥量。
您的 idle 函数锁定 mutex,然后在您的 pthread_cond_wait[= 上自旋锁23=]。然后,当调度程序愿意时,允许执行 push 函数,但是 push 函数所做的第一件事是尝试获取 互斥。不幸的是,mutex 已经被 idle 线程拥有。因此 push 线程阻塞,等待 mutex 被释放,这永远不会发生,因为空闲函数是 [= 上的自旋锁定12=]pthread_cond_wait.
在 pop
函数中控制 head 是否为 null
后,您的互斥对象应该以适当的方式锁定,否则它会保持阻塞状态。而且,pthread_cond_signal
函数可能会被一个线程调用,无论它当前是否拥有调用 pthread_cond_wait
的线程在其等待期间与条件变量相关联的互斥体;但是,如果需要可预测的调度行为,则该互斥锁会被调用 pthread_cond_signal
.
的线程锁定
我的多线程代码有问题,有一个死锁,但我不知道如何修复它,因为我是 pthreads 的新手。
下面的代码显示了一个名为 "idle" 的函数,它正在等待一个模拟进程被放置在就绪队列中,推送函数应该将该进程放置在队列中,然后发出信号表明有一个进程已准备好安排。
下面是导致死锁的两个函数:
void push(pcb_t *pcb) {
pthread_mutex_lock(&queue_mutex);
if (head == NULL) {
head = pcb;
tail = pcb;
} else {
pcb_t *old_tail = tail;
tail = pcb;
old_tail->next = tail;
}
pthread_cond_signal(&proc_ready);
pthread_mutex_unlock(&queue_mutex);
}
extern void idle(unsigned int cpu_id)
{
pthread_mutex_lock(&queue_mutex);
while(head == NULL) {
pthread_cond_wait(&proc_ready, &queue_mutex);
}
pthread_mutex_unlock(&queue_mutex);
schedule(cpu_id);
/*
* idle() must block when the ready queue is empty, or else the CPU threads
* will spin in a loop. Until a ready queue is implemented, we'll put the
* thread to sleep to keep it from consuming 100% of the CPU time. Once
* you implement a proper idle() function using a condition variable,
* remove the call to mt_safe_usleep() below.
*/
}
这是 gdb 回溯:
Thread 2 (Thread 0xb7df7b40 (LWP 3443)):
#0 0xb7fdd424 in __kernel_vsyscall ()
No symbol table info available.
#1 0xb7fb59e2 in __lll_lock_wait ()
at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:144
No locals.
#2 0xb7fb1267 in _L_lock_847 () from /lib/i386-linux-gnu/libpthread.so.0
No symbol table info available.
#3 0xb7fb10a0 in __GI___pthread_mutex_lock (mutex=0x804c75c <queue_mutex>)
at ../nptl/pthread_mutex_lock.c:79
__PRETTY_FUNCTION__ = "__pthread_mutex_lock"
type = 0
id = <optimized out>
#4 0x080489d9 in idle (cpu_id=0) at student.c:116
No locals.
#5 0x08048f65 in simulator_cpu_thread (cpu_id=0) at os-sim.c:259
state = CPU_IDLE
#6 0x08049b4a in simulator_cpu_thread_func (data=0x0) at os-sim.c:618
No locals.
#7 0xb7faef70 in start_thread (arg=0xb7df7b40) at pthread_create.c:312
__res = <optimized out>
pd = 0xb7df7b40
now = <optimized out>
unwind_buf = {cancel_jmp_buf = {{jmp_buf = {-1208217600, -1210090688, 4001536,
-1210092504, -193645269, -1085428949}, mask_was_saved = 0}}, priv = {
pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0,
canceltype = 0}}}
not_first_call = <optimized out>
pagesize_m1 = <optimized out>
sp = <optimized out>
freesize = <optimized out>
---Type <return> to continue, or q <return> to quit---
__PRETTY_FUNCTION__ = "start_thread"
#8 0xb7ee5bee in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129
No locals.
Thread 1 (Thread 0xb7df8700 (LWP 3439)):
#0 0xb7fdd424 in __kernel_vsyscall ()
No symbol table info available.
#1 0xb7fb59e2 in __lll_lock_wait ()
at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:144
No locals.
#2 0xb7fb1267 in _L_lock_847 () from /lib/i386-linux-gnu/libpthread.so.0
No symbol table info available.
#3 0xb7fb10a0 in __GI___pthread_mutex_lock (mutex=0x804c75c <queue_mutex>)
at ../nptl/pthread_mutex_lock.c:79
__PRETTY_FUNCTION__ = "__pthread_mutex_lock"
type = 0
id = <optimized out>
#4 0x0804886f in push (pcb=0x804c660 <processes>) at student.c:42
No locals.
#5 0x08048acb in wake_up (process=0x804c660 <processes>) at student.c:205
No locals.
#6 0x08049a14 in simulate_io () at os-sim.c:590
completed = 0x804d0f8
pcb = 0x804c660 <processes>
#7 0x08048e0f in simulator_supervisor_thread () at os-sim.c:189
No locals.
#8 0x08048dcc in start_simulator (new_cpu_count=1) at os-sim.c:161
n = 1
__PRETTY_FUNCTION__ = "start_simulator"
#9 0x08048ba8 in main (argc=2, argv=0xbffff284) at student.c:240
cpu_count = 1
__PRETTY_FUNCTION__ = "main"
编辑:也使用 queue_mutex
的 pop 函数pcb_t * pop() {
pcb_t *pcb = NULL;
pthread_mutex_lock(&queue_mutex);
if (head == NULL) {
return NULL;
} else if (head == tail) {
pcb = head;
head = NULL;
tail = NULL;
} else {
pcb = head;
head = head->next;
}
pthread_mutex_unlock(&queue_mutex);
pcb->next = NULL;
return pcb;
}
在 head == NULL 情况下,您的 pop 函数不会解锁互斥量。
您的 idle 函数锁定 mutex,然后在您的 pthread_cond_wait[= 上自旋锁23=]。然后,当调度程序愿意时,允许执行 push 函数,但是 push 函数所做的第一件事是尝试获取 互斥。不幸的是,mutex 已经被 idle 线程拥有。因此 push 线程阻塞,等待 mutex 被释放,这永远不会发生,因为空闲函数是 [= 上的自旋锁定12=]pthread_cond_wait.
在 pop
函数中控制 head 是否为 null
后,您的互斥对象应该以适当的方式锁定,否则它会保持阻塞状态。而且,pthread_cond_signal
函数可能会被一个线程调用,无论它当前是否拥有调用 pthread_cond_wait
的线程在其等待期间与条件变量相关联的互斥体;但是,如果需要可预测的调度行为,则该互斥锁会被调用 pthread_cond_signal
.