A simple implementation of the producer/consumer pattern
Small nitpicks

Naming: Handler is very non-descriptive. Maybe try Consumer instead?
Naming: addItem does not describe a Consumers action, consume or pass would be a better fit IMHO

Design problems
Handler is a queue fused with a single consumer, so there will never be more than one consumer for the queue!.
If the consumer is not required to run on its own thread, the implementation could be simplified to:
template&lt;typename Item&gt;
class SingleConsumer {
private:
    std::function&lt;void(Item&amp;&amp;)&gt; consumer;
    std::mutex mut; // can be removed if consumer is thread-safe on its own

public:
    template&lt;typename Callable&gt;
    SingleConsumer(Callable&amp;&amp; callable) : consumer(std::forward&lt;Callable&gt;(callable)) {}

    void consume(Item&amp;&amp; item) {
        std::unique_lock&lt;std::mutex&gt; lock(mut); // not necessary if consumer is thread-safe on its own
        consumer(std::move(item));
    }
};

On the other hand, if the requirement is that the consumer has to run on its own thread, why fuse it with its own queue? If there is only one queue, you could run multiple consumers on it to share the workload if needed and/or producers by themselves don't have to decide which consumer to call!
template&lt;typename Item&gt;
class ConcurrentQueue {
private:
    std::mutex mut;
    std::queue&lt;Item&gt; queue;
    
public:
    ConcurrentQueue() : queue() {}
    
    bool try_pop(Item&amp; item) {
        std::unique_lock&lt;std::mutex&gt; lock(mut);
        if(queue.empty()) return false;
        item = queue.front();
        queue.pop();
    }
    
    void push(Item&amp;&amp; item) {
        std::unique_lock&lt;std::mutex&gt; lock(mut);
        queue.push(std::move(item));
    }
};

template&lt;typename Item&gt;
class Consumer {
private:
    std::thread consumer_thread;
    ConcurrentQueue&lt;Item&gt;&amp; queue;
    std::atomic&lt;bool&gt; is_running = ATOMIC_VAR_INIT(true);

public:
    template&lt;typename Callable&gt;
    Consumer(ConcurrentQueue&lt;Item&gt;&amp; q, Callable&amp;&amp; callable) : consumer_thread([callable]() {
        run(std::forward&lt;Callable&gt;(callable));
    }), queue(q) {}
    
    ~Consumer() {
        is_running = false;
        consumer_thread.join();
    }
    
    template&lt;typename Callable&gt;
    void run(Callable&amp;&amp; consumer) {
        Item item;
        while(is_running) {
            while(is_running &amp;&amp; !queue.try_pop(item)) /* do nothing */;
            if(!is_running) return;
            consumer(item);
        }
    }
};

Of course, this example can be expanded according to your needs!