1

我有生产者消费者问题需要稍作修改来解决 - 有许多并行生产者,但一个并行线程中只有一个消费者。当生产者在缓冲区中没有位置时,它会简单地忽略元素(不等待消费者)。我已经写了一些 C 伪代码:

struct Element
{
   ULONG content;
   volatile LONG bNew;
}

ULONG max_count = 10;
Element buffer* = calloc(max_count, sizeof(Element));
volatile LONG producer_idx = 0;
LONG consumer_idx = 0;
EVENT NotEmpty;

BOOLEAN produce(ULONG content)
{
  LONG idx = InterlockedIncrement(&consumer_idx) % max_count;

  if(buffer[idx].bNew)
    return FALSE;
  buffer[idx].content = content;
  buffer[idx].bNew = TRUE;
  SetEvent(NotEmpty);
  return TRUE;
}

void consume_thread()
{
  while(TRUE)
  {
    Wait(NotEmpty);
    while(buffer[consumer_idx].bNew)
    {
      ULONG content = buffer[consumer_idx].content;
      InterlockedExchange(&buffer[consumer_idx].bNew, FALSE);
      //Simple mechanism for preventing producer_idx overflow
      LONG tmp = producer_idx;
      InterlockedCompareExchange(&producer_idx, tmp%maxcount, tmp);
      consumer_idx = (consumer_idx+1)%max_count;
      doSth(content);
    }
  }
}

我不能 100% 确定这段代码是正确的。你能看到任何可能发生的问题吗?或者也许这段代码可以用更好的方式编写?

4

2 回答 2

0

不要使用全局变量来实现你的目标,尤其是在多线程应用程序中!!!请改用 Semaphore,不要使用 Lock 而是使用 TryLock。如果 TryLock 失败,则意味着没有其他元素的空间,因此您可以跳过它。

在这里您可以找到有关 WinAPI 中信号量的信息,因为您可能会使用它: http: //msdn.microsoft.com/en-us/library/windows/desktop/ms686946 (v=vs.85).aspx
http: //msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx

您可以通过将 0 作为超时传递给 WaitForSingleObject 函数来实现 TryLock 功能。

于 2011-12-27T11:08:42.927 回答
0

请阅读:http ://en.wikipedia.org/wiki/Memory_barrier

C 和 C++ 标准不涉及多线程(或多处理器),因此,volatile 的有用性取决于编译器和硬件。尽管 volatile 保证 volatile 读取和 volatile 写入将按照源代码中指定的确切顺序发生,但编译器可能会生成代码(或 CPU 可能会重新排序执行),以便 volatile 读取或写入相对于非-volatile 读取或写入,因此限制了它作为线程间标志或互斥锁的用途。此外,由于缓存、缓存一致性协议和宽松的内存排序,不能保证其他处理器会以相同的顺序看到 volatile 读取和写入,这意味着单独的 volatile 变量甚至可能无法用作线程间标志或互斥体。

所以在一般情况下, volatile 不适用于 C。但它可以适用于某些特定的编译器/硬件和其他语言(例如 Java 5)。

另请参阅函数调用是内存屏障吗?

于 2011-12-27T12:13:16.563 回答