【问题标题】:Lock free atomic circular queue not working properly无锁原子循环队列无法正常工作
【发布时间】:2015-07-21 13:10:52
【问题描述】:

我尝试创建一个无锁原子循环队列,但它无法正常工作。

我创建了 2 个线程。一种用于推入队列,另一种用于从队列中弹出。但是;

问题: -当推送线程运行时,弹出线程没有机会运行。推送线程完全运行后,弹出线程运行,反之亦然。

我对 C++ 了解不多。那么,请您编辑我的代码以使其正常工作吗?

我使用的是 GCC 4.8.1

提前致谢。

代码:

#include <cstdlib>
#include <iostream>
#include <atomic>
#include <cstddef>
#include <thread>
#include <stdio.h>
#include <unistd.h>

#define capacity 1000



std::atomic<int> _head;
std::atomic<int> _tail;

int array[capacity];

int increment(int size)
{
    return (size+1)%capacity;
}

bool push(int *item)
{
    printf("Inside push\n");
    const int current_tail= _tail.load(std::memory_order_relaxed);
    const int next_tail=increment(current_tail);

    if(next_tail != _head.load(std::memory_order_acquire))
    {
         array[current_tail]=*item;
         _tail.store(next_tail,std::memory_order_release);

         return true;
    }

         return false; //Queue is Full
}

bool pop(int *item)
{   
      printf("Inside pop\n");
      const int current_head=_head.load(std::memory_order_relaxed);

      if(current_head==_tail.load(std::memory_order_acquire))
      {
          return false;//empty queue
      }

      *item=array[current_head];
      _head.store(increment(current_head),std::memory_order_release);

      return true;
}

bool isEmpty()
{
    return(_head.load()==_tail.load());
}

bool isFull()
{
    const int next_tail=increment(_tail);

    return (next_tail==_head.load());
}

bool isLockfree()
{
    return (_tail.is_lock_free() && _head.is_lock_free());
}

void *threadfunction_push()
{
    int item,i;
    bool flag;
    item=0;

    for(i=0;i<10000;i++)
    {
        while(isFull())
        std::this_thread::yield();

        ++item;
        push(&item);
        printf("pushed %d into queue\n",item);
        //usleep(100);

     }

}

void *threadfunction_pop()
{
    int item,i;

    item=0;
    for(i=0;i<10000;i++)
    {
       while(isEmpty())
             std::this_thread::yield();

       pop(&item);
       printf("popped %d from queue\n",item);


    }

     i=isLockfree();
     if(i)
        printf("Queue is lock Free");
}


int main(int argc, char** argv) 
{


    std::thread thread_push(threadfunction_push);
    std::thread thread_pop(threadfunction_pop);

    thread_push.join();
    thread_pop.join();

     return 0;
}

【问题讨论】:

  • 您知道,这个队列只适用于单个生产者和单个消费者吗?原因,它们一个接一个地运行的原因可能是循环太短了。当第二个线程被创建并计划运行时,第一个线程可能已经完成了。
  • 是的,这是单个生产者和单个消费者队列。我尝试增加循环计数器,但仍然无法正常工作。
  • 多少?您是如何确定它不起作用的?
  • 我尝试循环运行 100000 次,但前 100000 次仅运行 pop 线程,100000 次后 push 线程运行。我希望两个线程并行运行。
  • 这不是多线程编程的工作方式。你有像isEmpty 这样无用的函数这一事实表明你需要更好地理解并发编程的基本思想,可能来自教科书。

标签: c++ multithreading c++11


【解决方案1】:

您需要了解的第一件事是单核单线程处理器上的多线程。如果运行上述代码的处理器是单核单线程处理器,那么就不会有线程并行运行。这种处理器上的多线程有点像多进程概念。一次只运行一个线程,经过一段时间后,当第一个线程用完它的时间片时,操作系统会安排它进入睡眠状态,另一个线程启动并开始运行。这就是为什么您会看到“Pop 线程在 push 线程完全运行后运行,反之亦然。”

实际上,@MikeMB 已经指出了根本原因,因为运行循环太短了。如果您将阵列容量更改为 100,000,并将 pop 线程和 push 线程的循环计数器 i 增加到 1000 或更多,您将看到 pop 和 push 将交替运行。这是在我的带有 gcc4.9.2 的 vmware CentOS 6.4 上测试的。

祝你好运!

【讨论】:

  • 感谢@Zhichao Jia,我在双核处理器上运行它。当我在推送线程中设置100微秒的延迟时,我会显示它并行运行。
  • 它交替运行。但我想像 push(1),push(2),pop(1),push(3),pop(2)push(4)push 一样并行运行它们(5),pop(3)pop(4)...等。因为在我的应用程序中,我必须不断推送数据并且还需要并行弹出。
  • 我编辑了代码。你能uncomment usleep 运行吗?我想要的确切输出没有延迟。谢谢。
【解决方案2】:

当我添加一些命令行选项进行编译时,它工作正常。感谢大家的建议。

我使用以下命令编译。

g++ -std=c++11 -Full -Wall -pedantic -pthread -latomic main.cpp

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-01
    • 2014-12-02
    • 2013-08-09
    • 2013-10-30
    • 2013-10-19
    相关资源
    最近更新 更多