Home > Enterprise >  Store function inputs for threads
Store function inputs for threads

Time:01-03

Im trying to make a job system with a similar feature as std::thread where you can pass in parameters in a lambda which get captured e.g ( std::thread([&](int index){...} ), 5) )

This is the entire thread class

#include <condition_variable>
#include <functional>
#include <thread>

using uint = unsigned int;

class Thread {
public:

    Thread() {
        Start();
    }

    virtual ~Thread() {
        Shutdown();
    }

    void Start() {
        m_Thread = std::thread(&Thread::Poll, this);
    }

    void Poll() {
            {
                std::unique_lock<std::mutex> lock(m_Mutex);
                m_Condition.wait(lock, [this]() 
                {
                    return !m_Jobs.empty() && !m_Stop;
                });

                m_Job = m_Jobs.front();
                m_Jobs.pop_back();
            }
            m_Job(); // function<void()> type
        
    }

    void Execute(std::function<void()> New_Job) {
        { std::unique_lock<std::mutex> lock(m_Mutex);
            m_Jobs.push_back(New_Job);
        }
        m_Condition.notify_one();
    }

    template <typename Func, typename... Args>
    void ExecuteParams(Func f, Args... args) {  
        Execute(std::bind(f, args...));
    }

    void Wait() {
        while (!m_Jobs.empty() && !m_Stop) {
            Poll();
        }
    }


    void Shutdown() {
        {
            std::unique_lock<std::mutex> lock(m_Mutex);
            m_Stop = true;
        }

        m_Condition.notify_all();
        m_Thread.join();
    }
    

std::thread m_Thread;
std::mutex m_Mutex;
std::condition_variable m_Condition;
bool m_Stop = false;
std::function<void()> m_Job;
std::vector<std::function<void()>> m_Jobs;
};

This currently works sort of but if i pass in an index from a for loop for example, the index will just stay 0 for each job...

for(uint i = 0; i < 5; i  ) {
        MainThread.ExecuteParams([&](uint test)
        {
            std::unique_lock<std::mutex> L(lock);
            std::cout << "executing on thread " << std::this_thread::get_id() << std::endl;
            std::cout << test << std::endl;
        }, i);
    }   

CodePudding user response:

You have a very funny problem introduced :-)

m_Job = m_Jobs.front();
m_Jobs.pop_back();

You always pick the FIRST element to execute, but remove the last one. The result is, that you always execute the first element. I expect, that is not what you want! And as your loop inserts with 0 first, it looks like the var is not stored correctly, but it is. If you run your loop from 10..20 you will always see 10 instead.

BTW: You execute a lot of times your vector without locking the mutex. For example:

    void Wait() {
        while (!m_Jobs.empty() && !m_Stop) {
...

If you compile with -fsanitize=thread you get a long list of warnings.

  • Related