attempting first static thread_local not compiling

I am following a book that is attempting to teach me concurrency. I have gotten the example code in the book and matching github... but I find it usually doesn't compile straight away.. I am very close I think, but now need to learn how to instantiate the static thread_local custom typed queue..

https://github.com/anthonywilliams/ccia_code_samples/blob/main/listings/listing_9.6.cpp#L6-L7

That link is to the, I think, problem area.. and below is my attempt to instantiate along with the compiler / linker error

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
77
78
79
80
81
82
83
84
85
86
87
88
89
class thread_pool
{
    std::atomic_bool done;
    thread_safe_queue<function_wrapper> work_queue;
    std::vector<std::thread> threads;
    join_threads joiner;

    thread_safe_queue<function_wrapper> pool_work_queue;
    typedef std::queue<function_wrapper> local_queue_type;

    static thread_local std::unique_ptr<local_queue_type> local_work_queue;

    void worker_thread()
    {
        local_work_queue.reset(new local_queue_type);

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

        
        local_work_queue = std::make_unique<thread_pool::local_queue_type>();

        std::cout << "thread_pool initialized with " << thread_count << " threads." << std::endl;
        try
        {
            for(unsigned i=0;i<thread_count;++i)
            {
                threads.push_back(std::thread(&thread_pool::worker_thread,this));
            }
        }
        catch(...)
        {
            done=true;
            throw;
        }
    }

    ~thread_pool()
    {
        done=true;
        for(auto& thread : threads)
        {
            thread.join();
        }
    }

    template<typename FunctionType>
    std::future<typename std::result_of<FunctionType()>::type> submit(FunctionType f)
    {
        typedef typename std::result_of<FunctionType()>::type result_type;
        std::packaged_task<result_type()> task(f);
        std::future<result_type> res(task.get_future());
        if(local_work_queue)
        {
            local_work_queue->push(std::move(task));
        }
        else
        {
            pool_work_queue.push(std::move(task));
        }
        return res;
    }

    void run_pending_task()
    {
        function_wrapper task;
        if(local_work_queue && !local_work_queue->empty())
        {
            task=std::move(local_work_queue->front());
            local_work_queue->pop();
            task();
        }
        else if(pool_work_queue.try_pop(task))
        {
            task();
        }
        else
        {
            std::this_thread::yield();
        }
    }
};


The resulting error when I attempt to compile is as follows

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
% 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: /threadpool_local_queues/build
-- Configuring done
-- Generating done
-- Build files have been written to: /threadpool_local_queues/build
/usr/local/Cellar/cmake/3.18.4/bin/cmake -S/threadpool_local_queues -B/threadpool_local_queues/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_progress_start /threadpool_local_queues/build/CMakeFiles /threadpool_local_queues/build//CMakeFiles/progress.marks
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/Makefile2 all
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/depend
cd /threadpool_local_queues/build && /usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_depends "Unix Makefiles" /threadpool_local_queues /threadpool_local_queues /threadpool_local_queues/build /threadpool_local_queues/build /threadpool_local_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake --color=
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/build
[ 33%] Linking CXX executable bin/test_cpp_multi
/usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_link_script CMakeFiles/test_cpp_multi.dir/link.txt --verbose=1
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names 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 
Undefined symbols for architecture x86_64:
  "thread-local wrapper routine for thread_pool::local_work_queue", referenced from:
      thread_pool::thread_pool() in helloworld.cpp.o
      thread_pool::worker_thread() in helloworld.cpp.o
      thread_pool::run_pending_task() in helloworld.cpp.o
      std::__1::future<std::__1::result_of<std::__1::__bind<std::__1::list<int, std::__1::allocator<int> > (sorter<int>::*)(std::__1::list<int, std::__1::allocator<int> >&), sorter<int>*, std::__1::list<int, std::__1::allocator<int> > > ()>::type> thread_pool::submit<std::__1::__bind<std::__1::list<int, std::__1::allocator<int> > (sorter<int>::*)(std::__1::list<int, std::__1::allocator<int> >&), sorter<int>*, std::__1::list<int, std::__1::allocator<int> > > >(std::__1::__bind<std::__1::list<int, std::__1::allocator<int> > (sorter<int>::*)(std::__1::list<int, std::__1::allocator<int> >&), sorter<int>*, std::__1::list<int, std::__1::allocator<int> > >) 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


all help appreciated.. I kept attempting to post to stackoverflow but they just kept closing my question saying I need to instantiate the static variable

https://stackoverflow.com/questions/65942699/undefined-symbols-for-architecture-x86-64-on-gcc?noredirect=1#comment116670659_65942699

Comment led to https://stackoverflow.com/questions/65997338/how-to-properly-define-a-static-variable-in-c

https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix/12574407#12574407

Then I retried

https://stackoverflow.com/questions/65997338/how-to-properly-define-a-static-variable-in-c

Nothing seems to satisfy... I did bump up from C++11 to C+14 .. and that made VSCode at least seem happier in the linter..
Last edited on
 
static thread_local std::unique_ptr<local_queue_type> local_work_queue;


static variables declared within a class need to be defined outside of the class. So outside of the class but before int main() (not tried):

 
std::unique_ptr<thread_pool::local_queue_type> thread_pool::local_work_queue {};

thank you seeplus.

I took your advice finally (been slammed by things at work) .. and got a different error.. but this might be progress! I'll keep digging.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
std::unique_ptr<thread_pool::local_queue_type> thread_pool::local_work_queue {};

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


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
% sh compile.sh 
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Conan: Adjusting output directories
-- Conan: Using cmake targets configuration
-- Conan: Adjusting default RPATHs Conan policies
-- Conan: Adjusting language standard
-- Current conanbuildinfo.cmake directory: /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build
/usr/local/Cellar/cmake/3.18.4/bin/cmake -S/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues -B/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_progress_start /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build//CMakeFiles/progress.marks
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/Makefile2 all
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/depend
cd /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build && /usr/local/Cellar/cmake/3.18.4/bin/cmake -E cmake_depends "Unix Makefiles" /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake --color=
Dependee "/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles/test_cpp_multi.dir/DependInfo.cmake" is newer than depender "/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles/test_cpp_multi.dir/depend.internal".
Dependee "/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/build/CMakeFiles/test_cpp_multi.dir/depend.internal".
Scanning dependencies of target test_cpp_multi
/Applications/Xcode.app/Contents/Developer/usr/bin/make  -f CMakeFiles/test_cpp_multi.dir/build.make CMakeFiles/test_cpp_multi.dir/build
[ 33%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++  -I/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/./include -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -std=c++14 -o CMakeFiles/test_cpp_multi.dir/src/thread_safe_queue.cpp.o -c /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/src/thread_safe_queue.cpp
[ 66%] Building CXX object CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++  -I/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/./include -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk -std=c++14 -o CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o -c /Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/src/helloworld.cpp
/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/src/helloworld.cpp:206:61: error: non-thread-local declaration of 'local_work_queue' follows thread-local declaration
std::unique_ptr<thread_pool::local_queue_type> thread_pool::local_work_queue {};
                                                            ^
/Users/cpp-multithreading-in-action/ch09_06_threadpool_local_queues/src/helloworld.cpp:73:59: note: previous declaration is here
    static thread_local std::unique_ptr<local_queue_type> local_work_queue;
                                                          ^
1 error generated.
make[2]: *** [CMakeFiles/test_cpp_multi.dir/src/helloworld.cpp.o] Error 1
make[1]: *** [CMakeFiles/test_cpp_multi.dir/all] Error 2
make: *** [all] Error 2



EDIT:

oh my gosh, I googled a bit and saw this https://stackoverflow.com/a/43425308/389976 basically hinting that the definitions need to match.. ie the thread_local.. and it compiled now after I changed it to this!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
std::unique_ptr<thread_pool::local_queue_type> thread_local thread_pool::local_work_queue {};

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


thank you Seeplus!
Last edited on
Topic archived. No new replies allowed.