使用多线程处理对象数组 - 无效使用void表达式错误

时间:2017-10-08 18:27:16

标签: c++ arrays multithreading

我需要运行一些线程来处理对象数组。

所以我写了这段代码:

unsigned int object_counter = 0;
while(object_counter != (obj_max - left))
{
    thread genThread[thread_num];//create thread objects

    ///launch threads
    int thread_index = 0;
    for (; thread_index<thread_num; thread_index++)
    {
        genThread[thread_index] = thread(object[object_counter].gen_maps());//launch a thread

        object_counter++;
        if(object_counter == (obj_max - left)
        {
            break;
        }

    }
    ///finish threads
    for (; thread_index>0; thread_index--)
    {
        genThread[thread_index].join();

    }
}

基本上,有一个对象数组(对象数= obj_max - left)。 每个对象都有一个名为gen_maps()的函数(void type function),用于生成地形。

我想要做的是使用多线程从所有对象运行所有gen_maps()函数。

最大线程数存储在thread_num变量中。

但是当我尝试编译此代码时,我收到了错误:

error: invalid use of void expression
         genThread[thread_index] = thread(object[object_counter].gen_maps(), thread_index);//launch a thread
                                                                                         ^

如何解决此问题?

2 个答案:

答案 0 :(得分:0)

使用object[object_counter].gen_maps() 调用函数gen_maps并使用返回的值作为线程函数。显然gen_maps被声明返回void,这会导致您获得错误。

你需要传递一个指向函数的指针,然后将它应该被调用的对象作为参数传递给线程:

thread(&SomeClass::gen_maps, object[object_counter])

答案 1 :(得分:0)

使用较少数量的线程管理任意大量作业的更加可扩展的方法是使用线程池。

这是一个天真的实现(为了更好的效率,将有2个条件变量来管理控制和状态报告),它允许发起者添加任意数量的作业或线程,并等待所有作业完成。

#include <thread>
#include <condition_variable>
#include <mutex>
#include <vector>
#include <functional>
#include <deque>
#include <cassert>
#include <ciso646>
#include <iostream>

struct work_pool
{
    std::mutex control_mutex;
    std::condition_variable control_cv;
    std::deque<std::function<void()>> jobs;
    bool terminating = false;
    std::size_t running = 0;

    std::vector<std::thread> threads;

    work_pool(std::size_t n = std::thread::hardware_concurrency())
    {
        add_threads(n);
    }

    work_pool(const work_pool&) = delete;
    work_pool& operator=(const work_pool&) = delete;

    ~work_pool()
    {
        wait();
        shutdown();
    }


    void add_threads(std::size_t n)
    {
        while (n--)
        {
            threads.emplace_back([this]{
                run_jobs();
            });
        }
    }

    void run_jobs()
    {
        while (1)
        {
            auto lock = std::unique_lock(control_mutex);
            control_cv.wait(lock, [this] {
                return terminating or not jobs.empty();
            });

            if (terminating) return;

            ++running;

            auto job = std::move(jobs.front());
            jobs.pop_front();

            lock.unlock();

            job();

            lock.lock();

            --running;

            lock.unlock();

            control_cv.notify_one();
        }
    }

    void shutdown()
    {
        auto lock = std::unique_lock(control_mutex);
        terminating = true;
        lock.unlock();
        control_cv.notify_all();
        for (auto&& t : threads) {
            if (t.joinable()) {
                t.join();
            }
        }

        threads.clear();
    }

    void wait()
    {
        auto lock = std::unique_lock(control_mutex);
        control_cv.wait(lock, [this] {
            return jobs.empty() and not running;
        });
    }

    template<class F>
    void add_work(F&& f)
    {
        auto lock = std::unique_lock(control_mutex);
        assert(not terminating);
        jobs.emplace_back(std::forward<F>(f));
        lock.unlock();
        control_cv.notify_all();
    }
};

// dummy function for exposition
void generate_map() {}

int main()
{
    work_pool pool;

    for(int i = 0 ; i < 100000 ; ++i)
        pool.add_work(generate_map);

    pool.wait();

    // maps are now all generated

    std::cout << "done" << std::endl;   
}