我正在尝试实现一个简单的解决方案来解决哲学家进餐问题(有五位哲学家),我的解决方案基于以下逻辑:
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;
}
但是在调试这段代码的过程中出现了一个问题,chomptick[i]
在sem\u等待之前是
0
(
谁能帮我找出我的问题出在哪里?
你的实现是正确的,你的问题在于调试的方法。如果您使用gdb
,您将仅在一个线程上停止,而其余线程将继续执行,因此在您检查信号量的时间和您进入下一行的时间之间,其他线程将继续执行执行并可以更改您检查过的值。
为了有效地调试线程,您需要确保只有当前观察到的线程被调度,其余的线程被阻塞。为此,您需要在线程上停止后更改调度器锁定
。您可以将其设置为on
或step
,这取决于您希望线程完全停止,还是仅在单步操作期间停止(有关更多详细信息,请参阅帮助设置调度器锁定
)。
锁定线程后,您可以使用info threads
检查其余线程当时正在执行的操作。您可以使用线程
下面是将调度程序设置为
步骤
的示例。您可以看到,只有一个线程在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
如您所见,在执行下一步之后,我仍然在同一个线程上,其他线程没有进展。
我已经修改了代码,以使发生的事情更加可见,下面是我使用的代码:
#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;
}
问题内容: 我是一名编程初学者,对函数的返回值有疑问。 我正在学习Java。 我已经附上了我的书中具有经典选择排序功能的代码。 现在显然来自本书的代码可以正常工作。但是,主要功能中的以下三行是我的问题的基础: int [] a = new int [] {1,9,2,8,3,7,4,6,5}; 排序(a); if(ascending(a))System.out.println(“ Works”
问题内容: 在linux代码中,我记得听说过mutex_lock()周围有完整的内存屏障。我想确定它是否也在sem_xxx附近。 问题答案: 是的,在无竞争的情况下,它使用原子递增/递减,这当然有一个小数。对于有争议的情况,有一个对futex的系统调用,它也有一个成员。
问题内容: 今天,当我发现一段Python代码使用内置函数 作为变量标识符来存储列表推导的结果并且没有引发错误时,我偶然发现了这一点,因此我尝试了以下操作: 希望当我问为什么在Python中允许这种行为时,这是一个有效的问题。 或者更好的是,如何确保内置函数的确是真实的而不是不说,因此不会被偶然评估? 问题答案: Python希望您对您的代码负责,这就是为什么。Python没有私有属性,没有受保护
问题内容: 我有一个箭头函数,看起来像这样(简化): 但是当我调用它时,我得到: 为什么? 例: ( 注意: 对于上述带有箭头功能的 特定 问题,这是一个干净,规范的重复目标。) 问题答案: 当您使用箭头函数的函数主体版本(带有)时,没有暗示。您必须指定它。当您使用 简洁 主体(no )时,主体表达式的结果将由函数隐式返回。 因此,您可以使用显式的方式编写该代码: 或简洁的主体: 例子: 略 切线
问题内容: 我用 和做了一些测试 。他们似乎都慢于。是因为精度更高吗?计算斜边函数的方法是什么?令人惊讶的是,我在文档中找不到任何表明性能不佳的迹象。 问题答案: 这不是一个简单的sqrt函数。您应该检查此链接以实现算法:http : //www.koders.com/c/fid7D3C8841ADC384A5F8DE0D081C88331E3909BF3A.aspx 它具有while循环以检查收
为什么这个字符串是数字的?那些字符代表什么?