linux - 我的信号量模块没有正常工作(餐饮哲学家)

标签 linux multithreading pthreads deadlock semaphore

我正在实现一个信号量方法来理解同步和线程。

通过使用我的信号量,我试图解决 Dining Philosophers 问题。

我的计划是先制造僵局。

但我发现只有一位哲学家反复进食。

而且我通过使用其他同步问题检查了我的信号量是否工作得很好。我认为语法有问题。

请告诉我问题是什么。

这是我的代码。

dinig.c(包含main函数)

#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(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

enter image description here

最佳答案

一个问题是,在 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() 中“获取”筷子的代码在每个哲学家同时获取“左”筷子 (chopstick[ i]) 并最终永远等待获得“正确的”筷子 (chopstick[k]),因为所有的筷子都在某个哲学家的左手。

关于linux - 我的信号量模块没有正常工作(餐饮哲学家),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33533956/

相关文章:

regex - awk if 条件中的数值表达式

linux - 如何使用特定模式重命名一堆文件

c# - 为什么选择 System.Threading 而不是 BackgroundWorker?

c# - C# Parallel.ForEach 是否对集合的迭代使用相同的线程

c - 用C模拟javascript的setTimeout和setInterval

c++ - 当分配的字符串上带有指针的分配结构作为 pthread 的参数传递时,指针丢失

linux - 为什么要使用 pthread_mutex_lock,而同样的事情可以通过可编程的方式完成?

linux - 如何获取自上次使用 bash 修改文件以来的时间(以秒为单位)?

linux - 如何在Linux shell中获取两个文件同一列中相同值的计数?

android - 条件链单一且可完成