linker not finding reference, unless inline?

Hi All,

I had an example code snippet which I construct a work stealable queue .. all was fine when working on it in my MacOS environment.. now I want to start developing in Linux and my CMake routine is complaining.. I do not understand the error output here..

*helloworld.cpp*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...

#include "thread_safe_queue.cpp"
...
class thread_pool
{
    typedef function_wrapper task_type;
    
    std::atomic_bool done;
    thread_safe_queue<task_type> pool_work_queue;
    std::vector<std::unique_ptr<work_stealing_queue> > queues;
    std::vector<std::thread> threads;
    join_threads joiner;

    static thread_local work_stealing_queue* local_work_queue;
    static thread_local unsigned my_index;
   
    void worker_thread(unsigned my_index_)
    {
        my_index=my_index_;
        local_work_queue=queues[my_index].get();
        while(!done)
        {
            run_pending_task();
        }
    }
...

public:
    thread_pool():
        joiner(threads),done(false)
    {
        unsigned const thread_count=std::thread::hardware_concurrency();
...
};

template<typename T>
struct sorter
{
    thread_pool pool;
    
    std::list<T> do_sort(std::list<T>& chunk_data)
    {
...
    }
};

template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input)
{
    if(input.empty())
    {
        return input;
    }
    sorter<T> s;
    std::cout << "Beginning sort..." << std::endl;
    return s.do_sort(input);
}


int main()
{
    std::cout << "About to create a list that needs sorting...." << std::endl;
    std::list<int> my_list = {213,3,123,1,234232,41,0,-4,6,2,333,420,1337,88568568,4564564,456465456,33234234,2343,234222,3344555};
    std::cout << "Done creating my_list...." << std::endl;
    std::cout << "Submitting to sorter now" << std::endl;
    std::list<int> result = parallel_quick_sort(my_list);
    std::cout << "Now printing results" << std::endl;
    for (auto list_item : result){
        std::cout << list_item << "\n";
    }
    std::cout << "Finished" << std::endl;
}

//https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file




*thread_safe_queue.cpp*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <mutex>
#include <memory>
#include <condition_variable>
#include <queue>

template <typename T>
class thread_safe_queue {
    public:
        // constructor
        thread_safe_queue() {}
        thread_safe_queue(const thread_safe_queue& other)
        {
            std::lock_guard<std::mutex> lock{other.mutex};
            queue = other.queue;
        }

        void push(T new_value)
        {
            std::lock_guard<std::mutex> lock{mutex};
            queue.push(std::move(new_value));
            cond.notify_one();
        }

        void wait_and_pop(T& value)
        {
            std::unique_lock<std::mutex> lock{mutex};
            cond.wait(lock, [this]{ return !queue.empty(); });
            value = std::move(queue.front());
            queue.pop();
        }

        std::shared_ptr<T> wait_and_pop()
        {
            std::unique_lock<std::mutex> lock{mutex};
            cond.wait(lock, [this]{ return !queue.empty(); });
            std::shared_ptr<T> res{std::make_shared<T>(std::move(queue.front()))};
            queue.pop();
            return res;
        }

        bool try_pop(T& value)
        {
            std::lock_guard<std::mutex> lock{mutex};
            if (queue.empty())
                return false;
            value = std::move(queue.front());
            queue.pop();
            return true;
        }

        std::shared_ptr<T> try_pop()
        {
            std::lock_guard<std::mutex> lock{mutex};
            if (queue.empty()){
                return std::shared_ptr<T>{};
            }
            std::shared_ptr<T> res = std::make_shared<T>(std::move(queue.front()));
            queue.pop();
            return res;
        }

        bool empty() const
        {
            std::lock_guard<std::mutex> lock{mutex};
            return queue.empty();
        }

    private:
        mutable std::mutex mutex;
        std::condition_variable cond;
        std::queue<T> queue;
};





Error I get on compile step is

1
2
3
4
5
6
7
8
9
10
11
12
13
[100%] Linking CXX executable bin/test_cpp_multi
/usr/bin/cmake -E cmake_link_script CMakeFiles/test_cpp_multi.dir/link.txt --verbose=1
/usr/bin/c++    -g   CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o  -o bin/test_cpp_multi  -lpthread 
/usr/bin/ld: CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o: in function `TLS wrapper function for thread_pool::my_index':
helloworld.cpp:(.text._ZTWN11thread_pool8my_indexE[_ZTWN11thread_pool8my_indexE]+0x25): undefined reference to `thread_pool::my_index'
/usr/bin/ld: CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o: in function `TLS wrapper function for thread_pool::local_work_queue':
helloworld.cpp:(.text._ZTWN11thread_pool16local_work_queueE[_ZTWN11thread_pool16local_work_queueE]+0x25): undefined reference to `thread_pool::local_work_queue'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/test_cpp_multi.dir/build.make:99: bin/test_cpp_multi] Error 1
make[2]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/test_cpp_multi.dir/all] Error 2
make[1]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make: *** [Makefile:84: all] Error 2


My Cmake so far I've only had to add pthreads .. in other projects at least.. but this one seems to have some problem with my thread_pool local_work_queue?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cmake_minimum_required(VERSION 3.5)
project(test_cpp_multi)
add_compile_options(-std=c++14)

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

set(SOURCES
    src/thread_safe_queue.cpp
    src/helloworld.cpp
)

add_executable(test_cpp_multi ${SOURCES} )
target_link_libraries (test_cpp_multi LINK_PUBLIC pthread)

# Set the directories that should be included in the build command for this target
# when running g++ these will be included as -I/directory/path/

target_include_directories(test_cpp_multi
    PRIVATE
        ./include
)
Last edited on
tried just now upgrading to C++17 as per this suggestion.. https://stackoverflow.com/questions/55069128/undefined-reference-when-writing-reading-static-thread-local-class-member

with no effect

 
add_compile_options(-std=c++17)



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
(base) emcp@emcp-the-meg:~/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues$ 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: /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build
-- Conan: Compiler GCC>=5, checking major version 9
-- Conan: Checking correct version: 9
-- Configuring done
-- Generating done
-- Build files have been written to: /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build
/usr/bin/cmake -S/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues -B/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/progress.marks
/usr/bin/make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
/usr/bin/make -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/depend
make[2]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
cd /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake --color=
Dependee "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake" is newer than depender "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/depend.internal".
Dependee "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp" is newer than depender "CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o".
Clearing dependencies in "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/depend.make".
Scanning dependencies of target test_cpp_multi
make[2]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
/usr/bin/make -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/build
make[2]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
[ 33%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o
/usr/bin/c++   -I/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/./include  -g   -std=c++17 -o CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o -c /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/thread_safe_queue.cpp
[ 66%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o
/usr/bin/c++   -I/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/./include  -g   -std=c++17 -o CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o -c /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp
[100%] Linking CXX executable bin/test_cpp_multi
/usr/bin/cmake -E cmake_link_script CMakeFiles/test_cpp_multi.dir/link.txt --verbose=1
/usr/bin/c++    -g   CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o  -o bin/test_cpp_multi  -lpthread 
/usr/bin/ld: CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o: in function `TLS wrapper function for thread_pool::my_index':
helloworld.cpp:(.text._ZTWN11thread_pool8my_indexE[_ZTWN11thread_pool8my_indexE]+0x25): undefined reference to `thread_pool::my_index'
/usr/bin/ld: CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o: in function `TLS wrapper function for thread_pool::local_work_queue':
helloworld.cpp:(.text._ZTWN11thread_pool16local_work_queueE[_ZTWN11thread_pool16local_work_queueE]+0x25): undefined reference to `thread_pool::local_work_queue'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/test_cpp_multi.dir/build.make:99: bin/test_cpp_multi] Error 1
make[2]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/test_cpp_multi.dir/all] Error 2
make[1]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make: *** [Makefile:84: all] Error 2
Well your first problem is you both #include thread_safe_queue.cpp and compile thread_safe_queue.cpp

Pick one.

Ideally, you rename thread_safe_queue.cpp to thread_safe_queue.h and remove it as a source file in your CMake.
removing the line from CMake didn't have any effect on compiler output..

removing the #include did.. i think i need to go back to my book and recheck my work vs the authors

https://github.com/anthonywilliams/ccia_code_samples/blob/main/listings/listing_9.7.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 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: /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build
-- Conan: Compiler GCC>=5, checking major version 9
-- Conan: Checking correct version: 9
-- Configuring done
-- Generating done
-- Build files have been written to: /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build
/usr/bin/cmake -S/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues -B/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/progress.marks
/usr/bin/make -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
/usr/bin/make -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/depend
make[2]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
cd /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake --color=
Dependee "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake" is newer than depender "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/depend.internal".
Dependee "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp" is newer than depender "CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o".
Clearing dependencies in "/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build/CMakeFiles/test_cpp_multi.dir/depend.make".
Scanning dependencies of target test_cpp_multi
make[2]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
/usr/bin/make -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/build
make[2]: Entering directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
[ 33%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o
/usr/bin/c++   -I/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/./include  -g   -std=c++17 -o CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o -c /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/thread_safe_queue.cpp
[ 66%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o
/usr/bin/c++   -I/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/./include  -g   -std=c++17 -o CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o -c /home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp
/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp:122:5: error: ‘thread_safe_queue’ does not name a type
  122 |     thread_safe_queue<task_type> pool_work_queue;
      |     ^~~~~~~~~~~~~~~~~
/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp: In member function ‘bool thread_pool::pop_task_from_pool_queue(thread_pool::task_type&)’:
/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp:147:16: error: ‘pool_work_queue’ was not declared in this scope; did you mean ‘local_work_queue’?
  147 |         return pool_work_queue.try_pop(task);
      |                ^~~~~~~~~~~~~~~
      |                local_work_queue
/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp: In member function ‘std::future<typename std::result_of<FunctionType()>::type> thread_pool::submit(FunctionType)’:
/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/src/helloworld.cpp:204:13: error: ‘pool_work_queue’ was not declared in this scope; did you mean ‘local_work_queue’?
  204 |             pool_work_queue.push(std::move(task));
      |             ^~~~~~~~~~~~~~~
      |             local_work_queue
make[2]: *** [CMakeFiles/test_cpp_multi.dir/build.make:76: CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o] Error 1
make[2]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/test_cpp_multi.dir/all] Error 2
make[1]: Leaving directory '/home/emcp/Dev/git/EMCP/cpp-multithreading-in-action/ch09_07_work_stealing_queues/build'
make: *** [Makefile:84: all] Error 2
Last edited on
I got the code now to compile after re-reading a suggestion from a random stackoverflow post on a similar error.. so now I have

1
2
3
4
5
6
7
8
9
10
11
12
class thread_pool
{
    typedef function_wrapper task_type;
    
    std::atomic_bool done;
    thread_safe_queue<task_type> pool_work_queue;
    std::vector<std::unique_ptr<work_stealing_queue> > queues;
    std::vector<std::thread> threads;
    join_threads joiner;

    static inline thread_local work_stealing_queue* local_work_queue;
    static inline thread_local unsigned my_index;


but now seg faults

1
2
3
4
5
$ ./build/bin/test_cpp_multi 
About to create a list that needs sorting....
Done creating my_list....
Submitting to sorter now
Segmentation fault (core dumped)


seems, according to some help on discord I need to protect the thread_local queue via mutex.. as someone is accessing it when it's not allocated or something to that effect
Topic archived. No new replies allowed.