jeudi 3 décembre 2020

c++ cmake clang error linker command failed

I have a small test project that when I try to build complains

% sh compile.sh
-- Conan: Adjusting output directories
-- Conan: Using cmake targets configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /cpp-multithreading-in-action/ch4_threadsafe_queue/build
-- Configuring done
-- Generating done
-- Build files have been written to: /cpp-multithreading-in-action/ch4_threadsafe_queue/build
Scanning dependencies of target test_cpp_multi
[ 33%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o
[ 66%] Linking CXX executable bin/test_cpp_multi
Undefined symbols for architecture x86_64:
  "threadsafe_queue<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::wait_and_pop(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)", referenced from:
      prepare_data() in helloworld.cpp.o
      data_preparation_thread() in helloworld.cpp.o
      data_processing_thread() in helloworld.cpp.o
  "threadsafe_queue<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::push(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
      data_preparation_thread() in helloworld.cpp.o
      _main in helloworld.cpp.o
  "threadsafe_queue<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::threadsafe_queue()", referenced from:
      __GLOBAL__sub_I_helloworld.cpp in helloworld.cpp.o
  "threadsafe_queue<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::empty() const", referenced from:
      data_preparation_thread() in helloworld.cpp.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [bin/test_cpp_multi] Error 1
make[1]: *** [CMakeFiles/test_cpp_multi.dir/all] Error 2
make: *** [all] Error 2

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.12)
project(test_cpp_multi)
add_compile_options(-std=c++11)

# Using the "cmake" generator
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_executable(test_cpp_multi src/threadsafe_queue.cpp src/helloworld.cpp )

Helloworld.cpp

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>
#include <chrono>

#include <unistd.h>
#include "threadsafe_queue.h"

threadsafe_queue<std::string> source_queue;
threadsafe_queue<std::string> data_queue;

std::string prepare_data(){
    std::string top_value;
    source_queue.wait_and_pop(top_value);
    return top_value;
}

void data_preparation_thread()
{
    while(!source_queue.empty())
    {
        std::string const data=prepare_data();
        data_queue.push(data);
    }    
}

bool is_last_chunk(std::string data){
    if (data.compare(std::string("ENDOFLINE"))==0){
        return true;
    } else {
        return false;
    }
}

void process(std::string data){
    std::cout << data;
}

void data_processing_thread()
{
    while(true)
    {
        std::string data;
        data_queue.wait_and_pop(data);
        process(data);
        if(is_last_chunk(data)) {
            break;
        }
    }
}

int main(){
    
    for (int i=0 ; i<3; i++){
        std::string const data = "TEST";
        source_queue.push(data);
    }
    std::string const data = "ENDOFLINE";
    source_queue.push(data);

    std::thread data_proc_thread(data_processing_thread);
    std::thread data_prep_thread(data_preparation_thread);


    data_proc_thread.join();
    data_prep_thread.join();

}

threadsafe_queue.cpp

#include <queue>
#include <mutex>
#include <memory>
#include <condition_variable>

template <typename T>

class threadsafe_queue
{
private:
    std::mutex mut;
    std::queue<T> data_queue;
    std::condition_variable data_cond;

public:
    threadsafe_queue()
    {
    }
    threadsafe_queue(threadsafe_queue const &other)
    {
        std::lock_guard<std::mutex> lk(other.mut);
        data_queue = other.data_queue;
    }
    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(mut);
        data_queue.push(new_value);
        data_cond.notify_one();
    }
    void wait_and_pop(T &value)
    {
        std::unique_lock<std::mutex> lk(mut);
        data_cond.wait(lk, [this] { return !data_queue.empty(); });
        value = data_queue.front();
        data_queue.pop();
    }
    std::shared_ptr<T> wait_and_pop()
    {
        std::unique_lock<std::mutex> lk(mut);
        data_cond.wait(lk, [this] { return !data_queue.empty(); });
        std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
        data_queue.pop();
        return res;
    }

    bool try_pop(T &value)
    {
        std::lock_guard<std::mutex> lk(mut);
        if (data_queue.empty())
            return false;
        value = data_queue.front();
        data_queue.pop();
        return true;
    }
    std::shared_ptr<T> try_pop()
    {
        std::lock_guard<std::mutex> lk(mut);
        if (data_queue.empty())
            return std::shared_ptr<T>();
        std::shared_ptr<T> res(std::make_shared<T>(data_queue.front()));
        data_queue.pop();
        return res;
    }
    bool empty() const
    {
        std::lock_guard<std::mutex> lk(mut);
        return data_queue.empty();
    }
};

threadsafe_queue.h

#include <memory>

template<typename T>
class threadsafe_queue {
    public:
        threadsafe_queue();
        threadsafe_queue(const threadsafe_queue&);
        threadsafe_queue& operator=(const threadsafe_queue&) = delete;
        void push(T new_value);
        bool try_pop(T& value);
        std::shared_ptr<T> try_pop();
        void wait_and_pop(T& value);
        std::shared_ptr<T> wait_and_pop();
        bool empty() const;
};

Any help is appreciated.

Aucun commentaire:

Enregistrer un commentaire