0

I'm aware this is an often asked question, but none of the solutions in SO solves my problem.

I'm currently making a thread pool implementation with definitions and declarations in different files to keep my project organised. However, my linker says that I have an undefined reference to a function to push a task into the thread pool. This sort of issue is easily fixable by adding the definition file (.cpp) to the compilation command or fixing the definition and declaration functions to have the exact same parameters, return type, etc...

But in my case, I HAVE included the definition file to my compilation command, and I've declared and defined my thread pool class functions exactly as how it should be.

pool.hpp:

#pragma once

#include <vector>
#include <deque>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <functional>
    
class threadpool {
    private:
        static std::vector<std::thread> threads;
        static std::deque<std::function<void()>> jobs;
        static std::mutex queue_mtx;
        static std::condition_variable mtx_condition;
        static bool stop;

    public:
        threadpool(int threadcount);
    
        ~threadpool();

        template<typename F, typename... Args>
        void push(F&& f, Args&&... args);
};

pool.cpp:

#include "pool.hpp"

#include <future>
#include <thread>
#include <mutex>
#include <deque>
#include <atomic>
#include <vector>

#include <iostream>

std::vector<std::thread> threadpool::threads;
std::deque<std::function<void()>> threadpool::jobs;
std::mutex threadpool::queue_mtx;
std::condition_variable threadpool::mtx_condition;
bool threadpool::stop;

threadpool::threadpool(int threadcount) {
    stop = false;
    for (size_t i = 0; i < threadcount; ++i) {
        threads.emplace_back([this] {
            while (true) {
                std::function<void()> task;
                {
                    std::unique_lock<std::mutex> lock(queue_mtx);
                    mtx_condition.wait(lock, [this] { return stop || !jobs.empty(); });
                    if (stop && jobs.empty()) { return; }
                    task = std::move(jobs.front());
                    jobs.pop_front();
                }
                task();
            }
        });
    };
}

threadpool::~threadpool() {
    {
        std::unique_lock<std::mutex> lock(queue_mtx);
        stop = true;
    }
    mtx_condition.notify_all();
    for (std::thread &thread : threads) {
        thread.join();
    }
}

template<typename F, typename... Args>
void threadpool::push(F&& f, Args&&... args) {
    auto task = std::make_shared<std::packaged_task<void()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
    {
        std::unique_lock<std::mutex> lock(queue_mtx);
        //if (stop) { OUT::error("Cannot push tasks into a deleted thread pool, aborting."); }
        jobs.emplace_back([task](){ (*task)(); });
    }
    mtx_condition.notify_one();
}";

main.cpp:

#include "pool.hpp"

#include <thread>
#include <chrono>
#include <iostream>

void await(int m) {
    std::this_thread::sleep_for(std::chrono::milliseconds(m));

}

int main() {
    threadpool pool(std::thread::hardware_concurrency());
    for (size_t i = 0; i < 50; i++) {
        pool.push(await, 500);
    }
    return 0;
}

This is just a proof of concept code to show my issue, but it's essentially the same problem I'm facing in my project.

I've done a bit of digging with some trial and error and I highly suspect that the parameters to the push function is what's causing the linker error:

/usr/bin/ld: /tmp/ccHliS99.o: in function `main':
main.cpp:(.text+0x6d): undefined reference to `void threadpool::push<void (&)(int), int>(void (&)(int), int&&)'
collect2: error: ld returned 1 exit status

Even though the push function parameters are exactly the same in the files, I still can't figure out how to fix the error. I found this out by commenting out the code inside the definition of the push function, and it still gives me an error, so I highly suspect the parameters to be the cause of the linker issue. This is my compilation command:

g++ main.cpp pool.cpp -o main && ./main
BadUsernameIdea
  • 182
  • 1
  • 12

0 Answers0