4

Basically what I would like to do is write a for loop that spawns multiple threads. The threads must call a certain function multiple times. So in other words I need each thread to call the same function on different objects. How can I do this using std::thread c++ library?

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
user2481095
  • 2,024
  • 7
  • 22
  • 32

3 Answers3

11

You can simply create threads in a loop, passing different arguments each time. In this example, they are stored in a vector so they can be joined later.

struct Foo {};

void bar(const Foo& f) { .... };

int main()
{
  std::vector<std::thread> threads;
  for (int i = 0; i < 10; ++i)
    threads.push_back(std::thread(bar, Foo()));

  // do some other stuff

  // loop again to join the threads
  for (auto& t : threads)
    t.join();
}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
1

Make a loop, each iteration constructing a separate thread object, all with the same function but different object as argument.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Why can't I use the same argument? – tomtom1-4 Mar 17 '22 at 12:26
  • 1
    @tomtom1-4 If you define an object inside the loop, you are passing different objects ("different argument") to the threads. Even if the name of the object is the same inside the loop, the object itself will be created, copied (to the thread), and destructed each iteration of the loop. If you look at the example in [juanchopanza answer](https://stackoverflow.com/a/19675166/440558), you will see that each iteration he does `Foo()` to create an object, so while he pass "the same argument" it's in fact different objects. – Some programmer dude Mar 17 '22 at 16:27
0

If you want to use some of C++11 stuff as well as utilize great power of std::function + std::bind you could try something like this:

#include <thread>
#include <functional>
#include <iostream>
#include <vector>
#include <memory>

typedef std::function<void()> RunningFunction;

class MyRunner 
{
private:
    MyRunner(const MyRunner&);
    MyRunner& operator=(const MyRunner&);
    std::vector<std::thread> _threads;

public:

    MyRunner(uint32_t count, RunningFunction fn) : _threads()
    {
        _threads.reserve(count);
        for (uint32_t i = 0; i < count; ++i)
            _threads.emplace_back(fn);
    }

    void Join()
    {
        for (std::thread& t : _threads)
            if (t.joinable())
                t.join();
    }
};

typedef std::shared_ptr<MyRunner> MyRunnerPtr;

class Foo
{
public:
    void Bar(uint32_t arg)
    {
        std::cout << std::this_thread::get_id() << " arg = " << arg << std::endl;
    }
};


int calcArg()
{
    return rand() % UINT32_MAX;
}

int main(int argc, char** argv)
{
    std::vector<Foo> objs;

    for (uint32_t i = 0; i < 32; ++i)
        objs.emplace_back(Foo());

    std::vector<MyRunnerPtr> runners;

    for (Foo& obj : objs)
    {
        const uint32_t someArg = calcArg();
        runners.emplace_back(std::make_shared<MyRunner>(1, std::bind(&Foo::Bar, &obj, someArg)));
    }

    for (MyRunnerPtr& runner : runners)
        runner->Join();
}
Alexey Zhivotov
  • 101
  • 1
  • 5