我的信号量模块没有正常工作(餐饮哲学家)
My semaphore module is not working properly(Dining philosopher)
我正在实现一个信号量方法来理解同步和线程。
通过使用我的信号量,我试图解决 Dining Philosophers 问题。
我的计划是先制造僵局。
但是我发现只有一个哲学家反复吃
并且我通过使用其他同步问题检查了我的信号量是否工作得很好。我觉得语法有点问题。
请告诉我问题是什么。
这是我的代码。
dinig.c(包括主函数)
#include "sem.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static tsem_t *chopstick[5];
static tsem_t *updating;
static int update_status (int i, int eating)
{
static int status[5] = { 0, };
static int duplicated;
int idx;
int sum;
tsem_wait (updating);
status[i] = eating;
/* Check invalid state. */
duplicated = 0;
sum = 0;
for (idx = 0; idx < 5; idx++)
{
sum += status[idx];
if (status[idx] && status[(idx + 1) % 5])
duplicated++;
}
/* Avoid printing empty table. */
if (sum == 0)
{
tsem_signal (updating);
return 0;
}
for (idx = 0; idx < 5; idx++)
fprintf (stdout, "%3s ", status[idx] ? "EAT" : "...");
/* Stop on invalid state. */
if (sum > 2 || duplicated > 0)
{
fprintf (stdout, "invalid %d (duplicated:%d)!\n", sum, duplicated);
exit (1);
}
else
fprintf (stdout, "\n");
tsem_signal (updating);
return 0;
}
void *thread_func (void *arg)
{
int i = (int) (long) arg;
int k = (i + 1) % 5;
do
{
tsem_wait (chopstick[i]);
tsem_wait (chopstick[k]);
update_status (i, 1);
update_status (i, 0);
tsem_signal (chopstick[i]);
tsem_signal (chopstick[k]);
}
while (1);
return NULL;
}
int main (int argc,
char **argv)
{
int i;
for (i = 0; i < 5; i++)
chopstick[i] = tsem_new (1);
updating = tsem_new (1);
for (i = 0; i < 5; i++)
{
pthread_t tid;
pthread_create (&tid, NULL, thread_func, (void *) (long) i);
}
/* endless thinking and eating... */
while (1)
usleep (10000000);
return 0;
}
sem.c(包括信号量方法)
#include "sem.h"
.
sem.h(Header 对于 sem.c)
#ifndef __SEM_H__
#define __SEM_H__
#include <pthread.h>
typedef struct test_semaphore tsem_t;
tsem_t *tsem_new (int value);
void tsem_free (tsem_t *sem);
void tsem_wait (tsem_t *sem);
int tsem_try_wait (tsem_t *sem);
void tsem_signal (tsem_t *sem);
#endif /* __SEM_H__ */
编译命令
gcc sem.c dining.c -pthread -o dining
一个问题是,在 tsem_wait()
中,您在锁之外有以下代码序列:
while(sem->count <= 0)
continue;
无法保证程序会真正重新读取 sem->count
- 编译器可以自由生成执行以下操作的机器代码:
int temp = sem->count;
while(temp <= 0)
continue;
事实上,这很可能会在优化构建中发生。
尝试将繁忙的等待循环更改为类似这样的内容,以便在持有锁的同时检查计数:
void tsem_wait (tsem_t *sem)
{
pthread_mutex_lock(&(sem->mutexLock));
while (sem->count <= 0) {
pthread_mutex_unlock(&(sem->mutexLock));
usleep(1);
pthread_mutex_lock(&(sem->mutexLock));
}
// sem->mutexLock is still held here...
sem->count--;
pthread_mutex_unlock(&(sem->mutexLock));
}
严格来说,您应该为 tsem_try_wait()
(您尚未使用)做类似的事情。
请注意,您可能需要考虑使用 pthread_cond_t
来提高等待柜台更改的效率。
最后,您在 thread_func()
中 'get' 筷子的代码在每个哲学家同时获得 'left' 筷子(chopstick[i]
) 最后永远等待拿到 'right' 筷子 (chopstick[k]
) 因为所有的筷子都在某个哲学家的左手上。
我正在实现一个信号量方法来理解同步和线程。
通过使用我的信号量,我试图解决 Dining Philosophers 问题。
我的计划是先制造僵局。
但是我发现只有一个哲学家反复吃
并且我通过使用其他同步问题检查了我的信号量是否工作得很好。我觉得语法有点问题。
请告诉我问题是什么。
这是我的代码。
dinig.c(包括主函数)
#include "sem.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static tsem_t *chopstick[5];
static tsem_t *updating;
static int update_status (int i, int eating)
{
static int status[5] = { 0, };
static int duplicated;
int idx;
int sum;
tsem_wait (updating);
status[i] = eating;
/* Check invalid state. */
duplicated = 0;
sum = 0;
for (idx = 0; idx < 5; idx++)
{
sum += status[idx];
if (status[idx] && status[(idx + 1) % 5])
duplicated++;
}
/* Avoid printing empty table. */
if (sum == 0)
{
tsem_signal (updating);
return 0;
}
for (idx = 0; idx < 5; idx++)
fprintf (stdout, "%3s ", status[idx] ? "EAT" : "...");
/* Stop on invalid state. */
if (sum > 2 || duplicated > 0)
{
fprintf (stdout, "invalid %d (duplicated:%d)!\n", sum, duplicated);
exit (1);
}
else
fprintf (stdout, "\n");
tsem_signal (updating);
return 0;
}
void *thread_func (void *arg)
{
int i = (int) (long) arg;
int k = (i + 1) % 5;
do
{
tsem_wait (chopstick[i]);
tsem_wait (chopstick[k]);
update_status (i, 1);
update_status (i, 0);
tsem_signal (chopstick[i]);
tsem_signal (chopstick[k]);
}
while (1);
return NULL;
}
int main (int argc,
char **argv)
{
int i;
for (i = 0; i < 5; i++)
chopstick[i] = tsem_new (1);
updating = tsem_new (1);
for (i = 0; i < 5; i++)
{
pthread_t tid;
pthread_create (&tid, NULL, thread_func, (void *) (long) i);
}
/* endless thinking and eating... */
while (1)
usleep (10000000);
return 0;
}
sem.c(包括信号量方法)
#include "sem.h"
.
sem.h(Header 对于 sem.c)
#ifndef __SEM_H__
#define __SEM_H__
#include <pthread.h>
typedef struct test_semaphore tsem_t;
tsem_t *tsem_new (int value);
void tsem_free (tsem_t *sem);
void tsem_wait (tsem_t *sem);
int tsem_try_wait (tsem_t *sem);
void tsem_signal (tsem_t *sem);
#endif /* __SEM_H__ */
编译命令
gcc sem.c dining.c -pthread -o dining
一个问题是,在 tsem_wait()
中,您在锁之外有以下代码序列:
while(sem->count <= 0)
continue;
无法保证程序会真正重新读取 sem->count
- 编译器可以自由生成执行以下操作的机器代码:
int temp = sem->count;
while(temp <= 0)
continue;
事实上,这很可能会在优化构建中发生。
尝试将繁忙的等待循环更改为类似这样的内容,以便在持有锁的同时检查计数:
void tsem_wait (tsem_t *sem)
{
pthread_mutex_lock(&(sem->mutexLock));
while (sem->count <= 0) {
pthread_mutex_unlock(&(sem->mutexLock));
usleep(1);
pthread_mutex_lock(&(sem->mutexLock));
}
// sem->mutexLock is still held here...
sem->count--;
pthread_mutex_unlock(&(sem->mutexLock));
}
严格来说,您应该为 tsem_try_wait()
(您尚未使用)做类似的事情。
请注意,您可能需要考虑使用 pthread_cond_t
来提高等待柜台更改的效率。
最后,您在 thread_func()
中 'get' 筷子的代码在每个哲学家同时获得 'left' 筷子(chopstick[i]
) 最后永远等待拿到 'right' 筷子 (chopstick[k]
) 因为所有的筷子都在某个哲学家的左手上。