Производитель-Потребитель в C++11

Я начал изучать манипулирование потоками и начал с простой программы, предназначенной для генерации случайных заглавных букв. Буквы генерируются случайным образом и добавляются в массив символов через производителя, и любые добавленные буквы выводятся в нижнем регистре. Потребитель просто выводит обычную заглавную букву из массива char. Пока что у меня есть следующее:

#include <iostream>           
#include <thread>             
#include <mutex>              
#include <condition_variable>
#include <random>

std::mutex mtx;
std::condition_variable cv;

int count = 0, buff_size = 0;
char* buff;

int random_int(int lower_bound) {
    std::random_device seed;
    std::mt19937 generator(seed());
    std::uniform_int_distribution<int> dist(lower_bound, std::nextafter(26, DBL_MAX));

    return dist(generator);
}

char random_char(int lower_bound) {
    return 'A' + (random_int(lower_bound) % 26);
}

/* Consumer

Reads characters from the buffer and prints them.

*/
void consume(int job) {
    std::unique_lock<std::mutex> lck(mtx);

    while (count == 0) {
        cv.wait(lck);
    }

    /*
    job + 1 = Running
    job = Ready
    */
    for (int i = 0; i < buff_size; i++) {
        std::cout << buff[i] << std::endl;
    }

    count--;
}

/* Producer

Randomly generates letters at (pos > buff_size & pos <= 26),
inserts them at the next available position in the buffer,
and then prints out the lowercase form of the inputted letter.

*/
void produce(int job) {
    std::unique_lock<std::mutex> lck(mtx);

    for (int i = 0; i < buff_size; i++) {
        buff[i] = random_char(buff_size);
        std::cout << tolower(buff[i]) << std::endl;
    }

    count++;
    cv.notify_one();
}

int main() {
    int buf_size = 0;

    std::cout << "The Producer-Consumer Problem (in C++11!)" << std::endl << "Enter the buffer size: ";
    std::cin >> buf_size;

    if (buf_size > 0 && buf_size <= 26) {
        // set the buffer size
        buff_size = buf_size;
        buff = new char[buff_size];
    }
    else {
        // rage quit
        exit(1);
    }

    std::thread production[10], processed[10];

    /* Initialize the arrays */
    for (int order = 0; order < buff_size; order++) {
        production[order] = std::thread(produce, order);
        processed[order] = std::thread(consume, order);
    }

    /* Join the threads to the main threads */
    for (int order = 0; order < buff_size; order++) {
        processed[order].join();
        production[order].join();
    }

    // free the allocated memory
    delete[] buff;
}

Мой вывод, однако, представляет собой смесь заглавных букв и случайных чисел. Что случилось? Это мой первый эксперимент, так что будьте осторожны. :)


person T145    schedule 17.09.2015    source источник
comment
Вы отметили C++11 в этом посте, и я также вижу buff = new char[buff_size] в вашем коде. Я бы рекомендовал использовать std::vector вместо массива или, по крайней мере, использовать интеллектуальные указатели, такие как std::unique_ptr или std::shared_ptr, для управления динамически размещаемыми вещами — они помогут вам не забыть их удалить.   -  person Steve    schedule 17.09.2015
comment
std::tolower возвращает int.   -  person zch    schedule 17.09.2015
comment
@Steve Спасибо за рекомендацию! Я собирался использовать подобную структуру данных, но, поскольку это моя первая попытка, я просто хотел визуализировать все вместе. Не уверен, что это скорее вопрос SO или CR. Не могли бы вы опубликовать ответ с некоторыми примерами этих структур данных? Последние два для меня новые.   -  person T145    schedule 17.09.2015
comment
Умный указатель в Википедии. См. также Google.   -  person Steve    schedule 18.09.2015


Ответы (1)


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

См. комментарий ЗЧ. Я думаю, он имеет в виду:

Вместо:

std::cout << tolower(buff[i]) << std::endl;

пытаться

std::cout << char(tolower(buff[i])) << std::endl;

or

std::cout << (char)tolower(buff[i]) << std::endl;

Поскольку тег C++, вам, возможно, следует использовать static_cast

std::cout << static_cast<char>(tolower(buff[i])) << std::endl;       
person 2785528    schedule 17.09.2015
comment
Поскольку это помечено как C++, static_cast должно быть предпочтительнее приведения в стиле C. - person Snps; 18.09.2015
comment
Это отлично работает, спасибо! Для будущих поколений: ‹a href=stackoverflow.com/questions/8091691/ ссылка на static_cast‹/a›. Было ли что-то, что, по вашему мнению, было неправильным или что можно было бы улучшить в моей фактической реализации производитель-потребитель? - person T145; 18.09.2015
comment
@T145 Существует еще один сайт Stack Exchange под названием Code Review, который был бы идеальным местом для получения отзывов о рабочем коде. - person Steve; 18.09.2015