Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 轻量级多读/单写器队列实现_Multithreading_Synchronization_Message Queue_Lock Free - Fatal编程技术网

Multithreading 轻量级多读/单写器队列实现

Multithreading 轻量级多读/单写器队列实现,multithreading,synchronization,message-queue,lock-free,Multithreading,Synchronization,Message Queue,Lock Free,我需要一个非常简单的多读/单写器队列实现,用于一个小线程池(相当于物理内核的数量)。现在我用条件变量实现了它,但我正在为未来的版本探索更轻的替代方案。我以如下内容结束(C伪代码): 这个实现正确吗?故障在哪里?主操作系统(Linux、BSD、OSX、Windows)提供了哪些轻量级的等待信号/唤醒信号设备 编辑 OS\u WAIT\u对象不强制为条件变量。这是一个简单的“进入睡眠状态,直到调度器唤醒您,因为其他人发送了一个信号”。条件变量的使用通常需要锁定(互斥)。因此,您的实现有一点意义(互斥

我需要一个非常简单的多读/单写器队列实现,用于一个小线程池(相当于物理内核的数量)。现在我用条件变量实现了它,但我正在为未来的版本探索更轻的替代方案。我以如下内容结束(C伪代码):

这个实现正确吗?故障在哪里?主操作系统(Linux、BSD、OSX、Windows)提供了哪些轻量级的等待信号/唤醒信号设备

编辑


OS\u WAIT\u对象
不强制为条件变量。这是一个简单的“进入睡眠状态,直到调度器唤醒您,因为其他人发送了一个信号”。

条件变量的使用通常需要锁定(互斥)。因此,您的实现有一点意义(互斥保护不需要CAS操作)。一些操作系统具有低级同步原语,这些原语位于互斥体和条件变量的下面,因此可以将它们直接用于SPMC队列。E、 g,Linux实现futex。@Tsyvarev我用互斥体和条件变量实现了我的工作队列。这不是我的工作队列,这是一个实验队列。OS_WAIT_对象不需要是条件变量。可以是操作系统可用的任何其他调度程序机制。简单地将操作系统等待对象解释为
进入睡眠状态直到…
基本上是无用的:如果在检查条件后但在调用此函数之前改变了信号,您将等待条件为真。因此,给定的实现通常不可能是正确的。您需要具有更复杂语义的等待机制,但这种语义依赖于操作系统。@Tsyvarev如果这种检查和进入睡眠是在用户空间中完成的,是的,它是可以发生的,但如果它是在内核空间中完成的,我不明白为什么会发生。我有嵌入式编程的经验,我的推理是,这种机制可以通过
HALT
INT
机器指令实现,不会出现问题。操作系统调度器不能执行类似的任务吗?内核代码中没有检查和睡眠之间的竞争是由某种关键部分提供的。用户空间对应的临界区主要由互斥体实现,其中条件变量用于等待。这将返回到您的工作实现。那么,你到底想要什么?
#define QUEUE_MAXSIZE 16

struct queue {
  OS_WAIT_OBJECT writer_waitobj;
  OS_WAIT_OBJECT reader_waitobj;
  size_t head;
  size_t tail;
  int data[QUEUE_MAXSIZE];
};

/* Called by a single writer. */
void enqueue(struct queue* queue, int value)
{
  /* If queue is full wait to avoid overwriting. */
  while (queue->head - queue->tail == QUEUE_MAXSIZE) {
    OS_WAIT(queue->writer_waitobj);
  }

  /* There are a single writer so synchronization isn't necessary. */
  queue->data[queue->head] = value;
  queue->head++;

  /* If queue was empty, signal the new state to one reader. */
  if (queue->head == queue->tail) {
    OS_AWAKE_ONE(queue->reader_waitobj);
  }
}

/* Called by (few) multiple readers. */
int dequeue(struct queue* queue)
{
  int value;
  const size_t my_tail = tail;

  /* If queue is empty readers must wait. */
  while (queue->head == my_tail) {
    OS_WAIT(queue->reader_waitobj)
  }

  /* Spin-lock readers synchronization. */
  do {
    value = queue->data[my_tail];
  } while (!CPU_COMPARE_AND_SWAP(queue->tail, my_tail, my_tail+1));

  /* If queue was full, signal the new state to writer. */
  if (queue->head - my_tail == QUEUE_MAXSIZE) {
    OS_AWAKE_ONE(queue->writer_waitobj);
  }

  return value;
}