Повторяющиеся симуляции с многопоточностью в C ++ - PullRequest
0 голосов
/ 21 апреля 2020

Я хочу смоделировать сценарий несколько раз, то есть repCnt = 100. Чтобы ускорить процесс, я хочу использовать несколько потоков, которые работают параллельно, и использовать мьютекс, когда они должны записать результаты в файл.

Их нужно вычесть из общего количества повторений, работая в группах с NUM_THREADS = 4. Записывать часть с мьютексом легко, но я не могу понять, как должен выглядеть основной l oop.

Вот начало:

NUM_THREADS = 4

void simulate(struct argType arg) {

}


int main() {
    // ... Some code here ... 

    vector<thread> vecOfThreads;

    for (rep = 0; rep < repCnt; rep++) {

        // Here they should work in groups of 4, i.e., rep = 1, 2, 3, 4

        // They need to call the simulate(struct argType) function while they are working

        // Once a thread is done, it should get the next task from the loop, i.e., rep = 5

    } 

    return 0;
}

Когда я искал пул потоков в C ++, все, что я нашел, было слишком много классов и методов. Должен быть гораздо более быстрый способ делать то, чего я хочу достичь. Может кто-нибудь помочь мне с самым простым и коротким кодом C ++?

Ответы [ 3 ]

1 голос
/ 21 апреля 2020

Использование только заголовка cxxpool :

#include "cxxpool.h"
#include <iostream>
#include <mutex>
#include <thread>

std::mutex cout_mutex;

struct some_arg {
    int i;
};

void simulate(const some_arg arg) {
    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "Hello from task #" << arg.i << " and thread " << std::this_thread::get_id() << std::endl;
}

int main() {
    cxxpool::thread_pool pool{4};
    for (int i = 0; i < 100; i++) {
        pool.push(simulate, some_arg{i});
    }
}
0 голосов
/ 21 апреля 2020

ИМХО, самое простое решение - использовать OpenMP - нет необходимости во внешних библиотеках, и оно поддерживается практически всеми компиляторами.

Эта страница представляет собой хорошее введение в OpenMP: http://jakascorner.com/blog/2016/04/omp-introduction.html Более подробную информацию о параллелизме l oop можно получить здесь: https://pages.tacc.utexas.edu/~eijkhout/pcse/html/omp-loop.html

0 голосов
/ 21 апреля 2020

Простой подход заключается в использовании трех циклов for в главном потоке и одного значения l oop в рабочих потоках:

В главном потоке:

1) Fill очередь с вашими единицами работы

2) Создать рабочие потоки и сохранить их в векторе

3) Дождаться завершения потоков

В рабочих потоках:

В любом случае oop попытайтесь исключить из очереди одну рабочую единицу за раз с помощью мьютекса. Если очередь пуста, вся обработка завершена.

#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>

struct Args {
    int num;

    Args(int num) : num(num) {}
};

void worker(std::queue<Args>& work, std::mutex& workMutex, std::vector<Args>& results, std::mutex& resultMutex) {
    while(true) {
           Args arg(-1);

           // dequeue work unit
           {
               std::lock_guard<std::mutex> lock(workMutex);
               if (work.empty()) break;
               arg = work.front();
               work.pop();
           }

           // process arg
           Args result(arg.num + 1);

           // save your results
           {
                std::lock_guard<std::mutex> lock(resultMutex);
                results.push_back(result);
           }
    }
}

int main() {
    std::vector<std::thread> threads;
    std::queue<Args> work;
    std::mutex workMutex;
    std::vector<Args> results;
    std::mutex resultMutex;

    const int NUMBER_OF_THREADS = 4;
    const int NUMBER_OF_WORK_UNITS = 100;

    // enqueue work units
    for (int i = 0; i < NUMBER_OF_WORK_UNITS; ++i) {
        work.push(Args(i));
    }

    // create worker threads
    for (int i = 0; i < NUMBER_OF_THREADS; ++i) {
        threads.emplace_back(worker, std::ref(work), std::ref(workMutex), std::ref(results), std::ref(resultMutex));
    }

    // wait for threads completing all work units
    for (std::thread& t : threads) {
        t.join();
    }

    // process results
    for (const Args& result : results) {
        std::cout << result.num << "\n";
    }
}
...