Использование std::thread и std::mutex. Поделитесь опытом

146
05 ноября 2019, 21:40

Решил разобраться в вопросе "Как писать эффективные многопоточные приложения/алгоритмы?"

Для эксперимента решено написать программу, которая генерирует последовательность байт заданного размера. Написаны функции:

  1. void GenSeqByte(std::ofstream &stream, size_t byte), которая разбивает задание на потоки (тело функции ниже);
  2. void GenAndWriteSeq(std::ofstream &stream, size_t &bytes, std::mutex &m), непосредственно генерирует последовательность.

Тут все понятно.

void GenSeqByte(std::ofstream &stream, size_t byte)
{
    std::mutex mtx;
    std::vector<std::thread> threads;
    for (size_t i = 0; i < std::thread::hardware_concurrency(); ++i) {
        threads.push_back(std::thread(GenAndWriteSeq, std::ref(stream), std::ref(byte), std::ref(mtx)));
    }
    for (auto &t : threads) {
        t.join();
    }
}

Функция GenAndWriteSeq(...) генерирует последовательность bufSize * sizeof(int) байт и записывает ее в выходной файл (предполагается, что это повысит эффективность, вместо постоянного вызова write()). Запись продолжается, пока мы не запишем нужное количество байт.

void GenAndWriteSeq(std::ofstream &stream, size_t &bytes, std::mutex &m)
{
    std::random_device seed;
    std::mt19937 gen(seed());
    std::uniform_int_distribution<int> dist;
    // 1 KByte buffer.
    constexpr size_t bufSize = 1024 / sizeof(int);
    int buf[bufSize];
    while (true)
    {
        for (size_t i = 0; i < bufSize; ++i) {
            buf[i] = dist(gen);
        }
        if (bytes > 0) {
            std::lock_guard<std::mutex> lck(m);
            if (bytes > 0) {
                stream.write(reinterpret_cast<char *>(buf), bytes > bufSize ? bufSize : bytes);
                if (bytes > bufSize) {
                    bytes -= bufSize;
                    continue;
                }
            }
        } 
        return;
    }
}

Прошу поделиться опытом и подсказать, как можно улучшить данный фрагмент кода. Лучшим вариантом будет подсказать, привести пример, и сослаться на какой нибудь источник (например, профессиональная литература).

Так же есть прямой вопрос. У нас имеется разделяемая между потоками память. Мы делим ее на непересекающиеся области и передаем разным потокам.

void foo(double *a, int b) { for (int i = 0; i < b; ++i) a[i] = 5; }
double array[512];
std::thread t1(foo, array, 256);
std::thread t2(foo, &array[256], 256);

Если оба потока не выходят за границы переданной им области и не происходит одновременной записи и чтения из памяти, то является ли такой код безопасным? Как безопасно передавать указатель в поток?

Пожалуйста, посоветуйте профессиональную литературу по данной тематике. Заранее благодарю всех за отклик.

READ ALSO
Не отображается закрытый член класса в описании дружественной функции

Не отображается закрытый член класса в описании дружественной функции

Столкнулся с проблемой: есть класс Вектор в нем содержится перегруженный оператор << для сцепленного вывода Вектора в программеВ описании...

127
Синхронизация потоков java [закрыт]

Синхронизация потоков java [закрыт]

Как сделать так чтобы программа собирала статистику использования слов с нескольких файлов в параллельных потокахПроверить каким образом...

133
TableView как выделять ячейку а не всю строку

TableView как выделять ячейку а не всю строку

Как в JavaFX TableView щелкая по ячейке выделять отдельно каждую ячейку, а не всю строкуВ дальнейшем я бы хотел реализовать копирование содержимого...

154
Проблемы с кодировкой (Spring-MVC PDF)

Проблемы с кодировкой (Spring-MVC PDF)

Нужно было вывести PDF файл в Spring MVCСейчас при выводе кириллица не отображается,просто исчезает а цифры остаются

114