我正在嘗試為哲學家進餐問題(有五個哲學家)實施一個簡單的解決方案,我的解決方案基于以下邏輯:
sem_t S[philosophers_number]
for each philosopher
{
while(TRUE)
{
if(current philosopher number != last philosopher)
{
thinking()
//i is number of current philosopher
sem_wait(take_chopstick(S[(i 1) % philosophers_number])) // right chopstick
sem_wait(take_chopstick(S[i])) // left chopstick
eat()
sem_post(put_chopstick(S[(i 1) % philosophers_number]))
sem_post(put_chopstick(S[i]))
}
else
{
thinking()
//i is number of current philosopher
sem_wait(take_chopstick(S[i])) // left chopstick
sem_wait(take_chopstick(S[(i 1) % philosophers_number])) // right chopstick
eat()
sem_post(put_chopstick(S[i]))
sem_post(put_chopstick(S[(i 1) % philosophers_number]))
}
}
每個哲學家首先思考的時間不到三秒鐘
然后如果右邊的筷子可用,哲學家會拿它,如果還有左邊的筷子可用,哲學家也會拿它,開始吃不到三秒鐘
然后哲學家會放下筷子,讓其他哲學家使用
為了避免回圈等待,對于最后一位哲學家,我將先拿起左筷子,然后再拿起右筷子,然后繼續相同的程序
這是我基于此邏輯實作的代碼:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#define THREADS 5
sem_t chopstick[THREADS];
void thinking(int ph_num)
{
printf("philosopher %d is thinking\n", ph_num);
int t = rand() % 3;
sleep(t);// up to 3 secs thinking
}
void eat(int ph_num)
{
printf("philosopher %d is eating\n", ph_num);
int t = rand() % 3;
sleep(t);// up to 3 secs eating
}
void *philosopher(void * ph_num )
{
int num=(int)ph_num;
while(1)
{
if(num < THREADS - 1)
{
thinking(num);
//pick up right chopstick
sem_wait(&chopstick[(num 1) % THREADS]);
//to make deadlocks absolutly happen, wait 1 sec then pickup left chopstick
sleep(1);
//pick up left chopstick
sem_wait(&chopstick[num]);
eat(num);
//put down right chopstick
sem_post(&chopstick[(num 1) % THREADS]);
//put down left chopstick
sem_post(&chopstick[num]);
}
else // last one pick left chopstick first, instead of right one to avoid cyclic wait
{
thinking(num);
//pick up left chopstick
sem_wait(&chopstick[num]);
//to make deadlocks absolutly happen, wait 1 sec then pickup left chopstick
sleep(1);
//pick up right chopstick
sem_wait(&chopstick[(num 1) % THREADS]);
eat(num);
//put down left chopstick
sem_post(&chopstick[num]);
//put down right chopstick
sem_post(&chopstick[(num 1) % THREADS]);
}
}
pthread_exit((void *)num);
}
int main ()
{
for(int i = 0; i < THREADS; i )
{
sem_init(&chopstick[i],0,1);
}
pthread_t threads[THREADS];
for(int i = 0; i < THREADS; i )
pthread_create(&threads[i], NULL, philosopher, (void *)i);
for(int i = 0; i < THREADS; i )
pthread_join(threads[i],NULL);
return 0;
}
But during debugging this code a problem happened, where chopstick[i] was 0 before sem_wait(&chopstick[num]) instead of blocking current thread, until a chopstick is available sem_wait() carried on, so a philosopher started eating without an actual chopstick.
Can anyone help me figure out where is my problem?
uj5u.com熱心網友回復:
您的實作是正確的,您的問題出在除錯方法上。如果您使用gdb,您將僅在一個執行緒上停止,而執行緒的其余部分將繼續執行,因此在您檢查信號量的時間和您進入下一行的時間之間,其他執行緒將繼續執行并可以更改您檢查過的值。
為了有效地除錯執行緒,您需要確保只有當前觀察到的執行緒被調度而其余執行緒被阻塞。為此,您需要scheduler-locking在停止執行緒后更改。您可以將其設定為on或step,具體取決于您是希望執行緒完全停止,還是僅在單步操作期間停止(help set scheduler-locking有關更多詳細資訊,請參閱 參考資料)。
一旦執行緒被鎖定,您就可以使用它info threads來檢查其余執行緒當時在做什么。您可以使用thread <<n>>更改為第 n 個執行緒并用于where檢查執行緒堆疊。
這是調度程式設定為 的示例step。您可以看到只有一個執行緒執行了該next命令。
(gdb) b 37
Breakpoint 1 at 0x1388: file test003.c, line 37.
(gdb) r
Starting program: /home/jordan/Development/tmptest/a.out
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7d90700 (LWP 4002538)]
philosopher 0 is thinking
[New Thread 0x7ffff758f700 (LWP 4002539)]
philosopher 1 is thinking
[New Thread 0x7ffff6d8e700 (LWP 4002540)]
philosopher 2 is thinking
[2] picking 3
[New Thread 0x7ffff658d700 (LWP 4002541)]
[Switching to Thread 0x7ffff6d8e700 (LWP 4002540)]
Thread 4 "a.out" hit Breakpoint 1, philosopher (ph_num=0x2) at test003.c:37
37 sem_wait(&chopstick[(num 1) % THREADS]);
(gdb) set scheduler-locking step
(gdb) info threads
Id Target Id Frame
1 Thread 0x7ffff7d91740 (LWP 4002534) "a.out" clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:78
2 Thread 0x7ffff7d90700 (LWP 4002538) "a.out" 0x00007ffff7e743bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0,
req=req@entry=0x7ffff7d8fe60, rem=rem@entry=0x7ffff7d8fe60) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
3 Thread 0x7ffff758f700 (LWP 4002539) "a.out" 0x00007ffff7e743bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0,
req=req@entry=0x7ffff758ee60, rem=rem@entry=0x7ffff758ee60) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
* 4 Thread 0x7ffff6d8e700 (LWP 4002540) "a.out" philosopher (ph_num=0x2) at test003.c:37
5 Thread 0x7ffff658d700 (LWP 4002541) "a.out" clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:78
(gdb) n
38 printf("[%i] picked %i\n", num, (num 1) % THREADS);
(gdb) info threads
Id Target Id Frame
1 Thread 0x7ffff7d91740 (LWP 4002534) "a.out" clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:78
2 Thread 0x7ffff7d90700 (LWP 4002538) "a.out" 0x00007ffff7e743bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0,
req=req@entry=0x7ffff7d8fe60, rem=rem@entry=0x7ffff7d8fe60) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
3 Thread 0x7ffff758f700 (LWP 4002539) "a.out" 0x00007ffff7e743bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0,
req=req@entry=0x7ffff758ee60, rem=rem@entry=0x7ffff758ee60) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
* 4 Thread 0x7ffff6d8e700 (LWP 4002540) "a.out" philosopher (ph_num=0x2) at test003.c:38
5 Thread 0x7ffff658d700 (LWP 4002541) "a.out" clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:78
如您所見,執行 next 后,我??仍停留在同一個執行緒上,而其他執行緒沒有進展。
我已經修改了代碼以使正在發生的事情更加明顯,這是我使用的代碼:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdlib.h>
#define THREADS 5
sem_t chopstick[THREADS];
void thinking(int ph_num)
{
printf("philosopher %d is thinking\n", ph_num);
int t = rand() % 3;
sleep(t);// up to 3 secs thinking
}
void eat(int ph_num)
{
printf("philosopher %d is eating\n", ph_num);
int t = rand() % 3;
sleep(t);// up to 3 secs eating
}
void *philosopher(void * ph_num )
{
int num=(int)ph_num;
while(1)
{
if(num < THREADS - 1)
{
thinking(num);
//pick up right chopstick
printf("[%i] picking %i\n", num, (num 1) % THREADS);
sem_wait(&chopstick[(num 1) % THREADS]);
printf("[%i] picked %i\n", num, (num 1) % THREADS);
//to make deadlocks absolutly happen, wait 1 sec then pickup left chopstick
//sleep(1);
//pick up left chopstick
printf("[%i] picking %i\n", num, num);
sem_wait(&chopstick[num]);
printf("[%i] picked %i\n", num, num);
eat(num);
//put down right chopstick
printf("[%i] put %i\n", num, (num 1) % THREADS);
sem_post(&chopstick[(num 1) % THREADS]);
//put down left chopstick
printf("[%i] put %i\n", num, num);
sem_post(&chopstick[num]);
}
else // last one pick left chopstick first, instead of right one to avoid cyclic wait
{
thinking(num);
//pick up left chopstick
printf("[%i] picking %i\n", num, num);
sem_wait(&chopstick[num]);
printf("[%i] picked %i\n", num, num);
//to make deadlocks absolutly happen, wait 1 sec then pickup left chopstick
//sleep(1);
//pick up right chopstick
printf("[%i] picking %i\n", num, num 1);
sem_wait(&chopstick[(num 1) % THREADS]);
printf("[%i] picked %i\n", num, num 1);
eat(num);
//put down left chopstick
printf("[%i] put %i\n", num, num);
sem_post(&chopstick[num]);
//put down right chopstick
printf("[%i] put %i\n", num, (num 1) % THREADS);
sem_post(&chopstick[(num 1) % THREADS]);
}
}
pthread_exit((void *)num);
}
int main ()
{
for(int i = 0; i < THREADS; i )
{
sem_init(&chopstick[i],0,1);
}
pthread_t threads[THREADS];
for(int i = 0; i < THREADS; i )
pthread_create(&threads[i], NULL, philosopher, (void *)i);
for(int i = 0; i < THREADS; i )
pthread_join(threads[i],NULL);
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/391654.html
標籤:c multithreading operating-system semaphore dining-philosopher
