0

I'm trying to run threads one after the other. I know I could do them serially but the whole point is so the commands don't block the UI.

However, in the implementation I came up with, I can't use std::thread because I can't pass threads as a parameter.

Is there another way I can do this?


This is my current implementation:

#include <mutex>
#include <thread>
#include <queue>

class ThreadQueue {
    std::queue <std::thread> threads;
    std::mutex mutex_add;
    std::mutex mutex_remove;

public:
   ThreadQueue() {}

    ~ThreadQueue() {}

    void add(std::thread thread) {
        mutex_add.lock();
        threads.push(thread);
        mutex_add.unlock();
    }

    std::thread remove() {
        mutex_remove.lock();
        std::thread thread = threads.front;
        threads.pop();
        thread.join();
        mutex_remove.unlock();
    }
};
14
  • 3
    Doesn't "serially" mean "one after the other"? Commented Jun 15, 2016 at 20:21
  • 5
    std::move() the threads into (and out of) the container. Commented Jun 15, 2016 at 20:22
  • 3
    Why can't you just one thread with a task queue? Commented Jun 15, 2016 at 20:23
  • 7
    You need to spend some time learning how Multithreading works, how c++11 threads work, and also some general information about c++; the code presented here suggests you don't currently have working knowledge sufficient to work with this kind of problem. Commented Jun 15, 2016 at 20:23
  • 6
    You should rather use a queue of functions and let one thread handle them all, one after the other. Commented Jun 15, 2016 at 20:23

2 Answers 2

4

I know I could do them serially but the whole point is so the commands don't block the UI.


Is there another way I can do this?

As it was already mentioned std::thread is a movable class type and you could use std::move() to transfer them in the queue.


But I don't think it's a good design to use a queue of std::thread instances.

Let's suppose you're placing a thread instance to that queue that utilizes a thread function, it will be started immediately. So then, what's the role of the queue here?
Should the thread pop itself from the queue as soon it was started? Who's going to join() it then?


As @alexeibs suggests you should have one thread, that executes UI background tasks (e.g. std::function objects) that are read from the queue.

You could even have such task queue being shared by multiple threads (aka thread pool), and maximize your available CPU cores' utilization (ideally you shouldn't have more active threads than CPU cores available).

The synchronization (mutexes, condition variables for notifying etc.) should be applied to the queue itself then.

Sign up to request clarification or add additional context in comments.

1 Comment

A possible implementation can use a boost::asio::io_service class: stackoverflow.com/a/37829164/3461423
2

You can move threads:

So you can simply fix your code like this.

void add(std::thread&& thread) {
          //        ^^   
        mutex_add.lock();
        threads.push(std::move(thread));
          //         ^^^^^^^^^
        mutex_add.unlock();
    }

But saying that there are other ways to solve this that may be better.

Rather than having a queue of threads that can be added and removed. Have an queue of jobs that are executed by a thread(s) owned by the object. Or you can simply use std::async() to start jobs in the background.

1 Comment

Well, suppose the thread is running now after the std::move() applied. What's the role of the queue then? When should the thread instance be pop()ed from it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.