【问题标题】:Shared memory access without semaphores没有信号量的共享内存访问
【发布时间】:2010-12-03 23:43:40
【问题描述】:

在 linux 中使用共享内存 api,如果我有一次写入(由 A 进程)而只有一次读取(由 B 进程),我还需要信号量吗?。 有没有一个例子可以说明,在没有信号量的情况下使用共享内存将在 linux 中进入死锁状态。

【问题讨论】:

  • 这两种读/写方法是否都在同一个对象/流上运行?是否可以同时运行多个进程 A/进程 B 实例?

标签: linux deadlock shared segment


【解决方案1】:

你的问题有点奇怪。首先,您不需要使用信号量,因为还有其他同步方法。

其次,不使用信号量通常不会导致死锁(除非您有信号量保护锁或出于某种原因使用其他同步方法)。使用同步方法往往会导致死锁,而不是没有死锁。

但是,当作者和读者争夺相同的资源时,您可以拥有所谓的Race Condition

现在关于一位作者和一位读者的问题:这可以使用互斥锁而不是信号量或任何其他数量的同步方法来完成。或者,如果您可以保证 B 进程的写入是原子的(即如果中断,它们不能使共享内存处于不一致的状态),则不需要同步。后一种情况不太可能,除非共享内存可以通过一条指令更新(有时甚至这还不够)。最好还是选择安全路线并以某种方式锁定对共享内存的访问。

【讨论】:

  • 非常感谢您的所有意见。结构 sharedStruct { bool isOk; };我的要求是肯定我将有一个进程读取(isOK)和另一个进程将在while循环中更新(isOK)。在阅读期间,我对变量的任何状态(真或假)都没有问题。我什至执行了进程 B 的多个副本(write isOK)并且没有发现任何问题。只是想了解必须需要哪些额外的代码来防止奇怪的行为......(竞争条件等)以及如何进入那种奇怪的状态。
【解决方案2】:

没有信号量(或更一般的 MUTEX),就不可能出现死锁。然而,可能会发生不一致/不连贯的数据。

例如,如果在共享内存位置中找到的对象类型是表示文本字符串的字符数组。有可能一个线程开始修改字符串,而另一个线程读取一次,得到一条奇怪的消息。

例如: 原文 “英国人来了!” 线程 1 开始更改为“警告所有爱国者!”但只能写 前 8 个字符。然后... 线程 2 读取 “警告alish来了!

编辑:请参阅 Falaina 的回应,该回应通常与此相呼应,并提供相关概念的指针和定义:竞争条件、原子性、互斥体...

【讨论】:

    【解决方案3】:

    只有一个进程写入,您将无法陷入死锁。

    但是,阅读器必须能够在阅读时处理部分写入的数据。这很可能是不可能的。

    此外,当您说一写一读时,您真的是指只读吗?如果你的意思是一个管道,一个进程将东西放在管道上,另一个从管道中删除东西,那么实际上两者都在写入共享内存。

    【讨论】:

      【解决方案4】:

      当您访问共享内存(除非您只读取)时,您需要防止并发写入或在写入期间读取。正确的做法是使用信号量。

      你可以使用这个 ScopedLock 类作为你的锁机制,只有一个进程可以同时拥有一个具有特定名称的作用域锁。如果另一个进程试图创建它,它将被阻塞,直到第一个进程作用域锁超出作用域。

      #include <semaphore.h>
      class ScopedLock{
          sem_t *sem;
      public:
          ScopedLock(const char* name) : sem(0)
          {
              sem = sem_open(name, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 1);
              if (sem == SEM_FAILED)
              {
                  printf("Error opening semaphore : %s\n", last_error_message());
                  throw "failed to create semaphore";
              }
      
              printf("locking interprocess lock...\n");
              if (-1 == sem_wait(sem))
              {
                  printf("Error locking semaphore : %s\n", last_error_message());
                  throw "failed to lock semaphore";
              }
              printf("interprocess lock locked\n");
          }
      
          ~ScopedLock()
          {
              if (sem)
              {
                  sem_post(sem);
                  printf("interprocess lock unlocked\n");
              }
          }
      
          // static destroy function, use for cleanup
          static void destroy(const char *name)
          {
              sem_t *sem = sem_open(name, O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
              if (sem != SEM_FAILED)
              {
                  sem_post(sem);
                  sem_destroy(sem);
              }
      
              if (-1 == sem_unlink(name))
              {
                  printf("Error destroying semphore: %s\n", last_error_message());
              }
          }
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-26
        • 1970-01-01
        相关资源
        最近更新 更多