2011-09-18 97 views
7

我正在尝试编写一个多生产者,多用户队列。 我在Arch Linux上使用G ++ 4.6,它也在G ++ 4.7上打破了。C++ 11原子。为什么会编译,但不能链接?

#include <atomic> 
#include <condition_variable> 
#include <memory> 
#include <mutex> 
#include <vector> 
#include <iostream> 
#include <string> 
#include <sstream> 

template <typename T> class concurrent_queue 
{ 
    public: 
    concurrent_queue(size_t n) : items(n), item_states(n), producer_index(0), consumer_index(0) { 
    } 
    virtual ~concurrent_queue() { 
    } 
    T * consume() { 
    auto index = consumer_index; 
    T * item = nullptr; 
    state_t state = USED; 

    // Extract item and block location. 
    while (!item_states[index].compare_exchange_strong(state, BLOCKED, std::memory_order_acquire, std::memory_order_acquire)) { 
     // Wait for an item to become available 
     std::unique_lock<std::mutex> lock(item_mutex); 
     has_items.wait(lock); 

     // Move to the newly available item (might already have been taken by another consumer). 
     index = consumer_index; 
    } 

    // Tell consumers to move to next location, wrap to beginning of circular buffer if necessary. 
    ++consumer_index; 
    consumer_index %= items.size(); 

    // Unblock index so that producers can write to it. 
    items[index] = nullptr; 
    return item; 
    } 
    void produce(T * value) { 
    items[producer_index] = value; 
    ++producer_index; 
    producer_index %= items.size(); 
    has_items.notify_one(); 
    } 
private: 
    typedef enum { 
    EMPTY, 
    USED, 
    BLOCKED 
    } state_t; 

    // Used as a buffer of items 
    std::vector<T* > items; 
    std::vector<std::atomic<state_t> > item_states; 
    size_t producer_index; 
    size_t consumer_index; 
    std::mutex item_mutex; 
    std::condition_variable has_items; 
}; 

// Test code 
using namespace std; 

template <typename T> void pop_n_print(concurrent_queue<T> & queue) { 
    stringstream message; 
    message << "popped " << *queue.consume() << endl; 
    cout << message.str(); 
} 

int main() 
{ 
    concurrent_queue<int> ints(5); 
    ints.produce(new int(1)); 
    ints.produce(new int(2)); 

    pop_n_print(ints); 
    pop_n_print(ints); 

    return 0; 
} 

我编译这段代码g++ --std=c++0x queue.cc -o test_queue,但我收到此错误信息:

/tmp/ccqCjADk.o: In function `concurrent_queue<int>::consume()': 
queue.cc:(.text._ZN16concurrent_queueIiE7consumeEv[concurrent_queue<int>::consume()]+0x9f): undefined reference to `std::atomic<concurrent_queue<int>::state_t>::compare_exchange_strong(concurrent_queue<int>::state_t&, concurrent_queue<int>::state_t, std::memory_order, std::memory_order)' 
collect2: ld returned 1 exit status 

我不知道这是为什么发生的,但它似乎表明,我需要对某事链接。 关于我要去哪里的任何想法都是错误的?任何指针都非常感谢。

+0

在Ubuntu上确认Natty 64bit gcc 4.6.1; Debian Sid 32bit gcc 4.6.1 – sehe

+0

我也是! g ++(Ubuntu/Linaro 4.6.3-1ubuntu5)4.6.3/Ubuntu 12.04.1 LTS x86_64 – nodakai

+0

已在4.7中修复http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49445 – nodakai

回答

10

因为std :: atomic只存在于某些Ts中,主要是数字类型。

+0

太棒了,谢谢!当我使用原子而不是枚举时,代码成功链接。我想我需要等待实现来支持其他数据类型? –

+0

是的,但它也不会支持每个数据类型,29.5指定了一些像T一样可复制的需求。 – PlasmaHH

+1

@Reuben:在这种情况下,我认为它不起作用的唯一原因是因为你的枚举是未命名的(它改变了它的链接)。尝试将'typedef enum {...} state_t;'更改为'enum state_t {...};'。 – ildjarn