2011-09-18 21 views
7

Sto tentando di scrivere una coda multiproduttore e multi-consumer. Sto usando G ++ 4.6 su Arch Linux, si interrompe anche su G ++ 4.7.C++ 11 Atomica. Perché questo compila, ma non il link?

#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; 
} 

compilo questo codice con g++ --std=c++0x queue.cc -o test_queue, ma ottengo questo messaggio di errore:

/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 

Io non sono sicuro perché questo sta avvenendo, ma sembra suggerire che ho bisogno di collegare contro qualcosa . Qualche idea su dove sto andando male? Qualsiasi suggerimento è molto apprezzato.

+0

confermato su Ubuntu Natty 64bit gcc 4.6.1; Debian Sid 32bit gcc 4.6.1 – sehe

+0

Anch'io! g ++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3/Ubuntu 12.04.1 LTS x86_64 – nodakai

+0

Risolto in 4.7 http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49445 – nodakai

risposta

10

Perché std :: atomic esiste solo per alcuni Ts, principalmente tipi numerici.

+0

Fantastico, grazie! Il codice si collega correttamente quando utilizzo l'atomico anziché l'enum. Suppongo di dover aspettare che l'implementazione supporti altri tipi di dati? –

+0

sì, ma non supporta anche tutti i tipi di dati, 29.5 specifica alcuni requisiti come T essendo banalmente copiabile. – PlasmaHH

+1

@Reuben: In questo caso, penso che l'unica ragione per cui non funzioni è perché l'enum è senza nome (che cambia il suo collegamento). Prova a cambiare 'typedef enum {...} state_t;' a 'enum state_t {...};'. – ildjarn

Problemi correlati