Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.61/18: Рейтинг темы: голосов - 18, средняя оценка - 4.61
0 / 0 / 0
Регистрация: 20.04.2014
Сообщений: 11

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

15.09.2014, 13:03. Показов 3613. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Реализовал схему производитель-потребитель. Есть класс генератора последовательных целых чисел, ограниченных максимальным занчением, на котором весь процесс останавливается.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include <iostream>
#include <thread>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <queue>
 
std::queue < int > produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
bool notified = false;
 
class Generator
{
    private:
        int num, max;
    public:
        Generator( int mx )
        {
            num = 0;
            max = mx;
        }
        int nextNumber()
        {
            return num++;
        }
        bool isEnd()
        {
            return num == max;
        }
};
 
class ThreadProducer
{
    private:
        std::thread thread;
        Generator *gen;
        int id;
        void function()
        {
            while ( !gen -> isEnd() )
            {
                //std::this_thread::sleep_for(std::chrono::milliseconds(1));
                std::unique_lock<std::mutex> lock(m);
                int current = gen -> nextNumber();
                std::cout << id << " producing " << current << '\n';
                produced_nums.push( current );
                notified = true;
                cond_var.notify_one();
            }
 
            done = true;
            cond_var.notify_one();
        }
    public:
        ThreadProducer( int id0, Generator *gn ) : thread( &ThreadProducer::function, this ), gen( gn ), id( id0 )
        {
        }
        void start()
        {
            thread.join();
        }
};
 
class ThreadConsumer
{
    private:
        std::thread thread;
        int id;
        void function()
        {
            std::unique_lock<std::mutex> lock(m);
            while (!done || !produced_nums.empty() ) {
                while (!notified) {  // loop to avoid spurious wakeups
                    cond_var.wait(lock);
                }
                while (!produced_nums.empty()) {
                    std::cout << id << " consuming " << produced_nums.front() << '\n';
                    produced_nums.pop();
                }
                notified = false;
            }
        }
    public:
        ThreadConsumer( int id0 ) : thread( &ThreadConsumer::function, this ), id( id0 )
        {
        }
        void start()
        {
            thread.join();
        }
};
 
int main()
{
    Generator generator( 15 );
    ThreadProducer p( 1, &generator );
    ThreadConsumer c( 1 );
 
    p.start();
    c.start();
    return 0;
}
Вопрос состоит в том, что поток-потребитель на срабатывает в момент производтсва, а ждет, пока производитель сгенерирует все данные и закончит выполнение. Если раскомментировать строку с ожиданием потока в милисекундах, то все норм, но все равно будет впустую тратиться время. Хочется, чтобы по мере заполнения очереди поток-потребитель начинал обрабатывать ее. И, если рассмотреть случай, когда у нас не один, а несколько потоков-потребителей, то они должны вытаскивать поочереди эти данные.
Короче говоря, как исправить ситуацию и как оптимизировать данную задачу, чтобы прирост был по времени, т.к. генератор, на самом деле, более сложный, чем я тут привел, да и операция потребителя с вытащинными данными тоже содержит более сложные махинации.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
15.09.2014, 13:03
Ответы с готовыми решениями:

Производитель потребитель
Задание: написать программу, в которой реализуется следующее: запись рандомного числа в массив, получение данного числа из массива и...

Идиома "Производитель - потребитель"
Добрый вечер всем. Продолжаю изучать многопоточное программирование в С++ и одновременно сталкиваться с миллионом проблем:). В этот раз...

Потребитель- производитель
Помогите пожалуйста в написании программы под ubuntu 11.04 сама задача(описание): http://sdmitri.ru/Erzeuger-Verbraucher-Problem

5
654 / 575 / 164
Регистрация: 13.12.2012
Сообщений: 2,124
15.09.2014, 15:35
а чему удивляться если start выполняется в одном потоке

Добавлено через 3 минуты
строки 45 73 взаимная блокировка

Добавлено через 2 минуты
Цитата Сообщение от mike_vik Посмотреть сообщение
C++
1
bool notified = false;
переменная общая
используется в 2х потоках, а мьютекса нет, или atomic_bool
0
 Аватар для DiffEreD
1458 / 795 / 257
Регистрация: 21.06.2011
Сообщений: 1,740
Записей в блоге: 2
15.09.2014, 15:39
Как то так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <iostream>
#include <thread>
#include <mutex>
#include <queue>
#include <memory>
#include <atomic>
 
std::queue < int > produced_nums;
std::mutex m;
std::atomic<bool> done{false};
 
class Generator
{
    private:
        int num, max;
    public:
        Generator( int mx )
        {
            num = 0;
            max = mx;
        }
        int nextNumber()
        {
            return num++;
        }
        bool isEnd()
        {
            return num == max;
        }
};
 
class ThreadProducer
{
    private:
        std::thread thread;
        std::unique_ptr<Generator> gen;
        int id;
        void function()
        {
            while ( !done )
            {
                {
                    std::lock_guard<std::mutex> lock(m);
                    done = gen->isEnd();
                    int current = gen -> nextNumber();
                    std::cout << id << " producing " << current << '\n';
                    produced_nums.push( current );
                }
                std::this_thread::yield();
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }
    public:
        ThreadProducer( int id0, Generator *gn ) : thread( &ThreadProducer::function, this ), id( id0 )
        {
            gen.reset(gn);
        }
        void start()
        {
            thread.join();
        }
        ~ThreadProducer()
        {
            if (thread.joinable()) thread.join();
        }
};
 
class ThreadConsumer
{
    private:
        std::thread thread;
        int id;
        void function()
        {
            while (!done || !produced_nums.empty()) {
                {
                    std::lock_guard<std::mutex> lock(m);
                    if (!produced_nums.empty()) {
                        std::cout << id << " consuming " << produced_nums.front() << '\n';
                        produced_nums.pop();
                    }
                }
                std::this_thread::yield();
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }
    public:
        ThreadConsumer( int id0 ) : thread( &ThreadConsumer::function, this ), id( id0 )
        {
        }
        void start()
        {
            thread.join();
        }
        ~ThreadConsumer()
        {
            if (thread.joinable()) thread.join();
        }
};
 
int main()
{
    ThreadProducer p( 1, new Generator(20));
    ThreadConsumer c( 2 );
    ThreadConsumer c2( 3 );
 
    p.start();
    c.start();
    c2.start();
    return 0;
}
0
 Аватар для Toshkarik
1181 / 894 / 94
Регистрация: 03.08.2011
Сообщений: 2,461
15.09.2014, 15:40
std::thread::join возвращает управление при завершении работы потока. Возможно Вам нужен std::thread::detach ?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
15.09.2014, 16:09
mike_vik,
Передалал немного твой пример (работа с несколькими Consumer, обработка событий и генерация свободны от блокировки).
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <iostream>
#include <thread>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <queue>
#include <unistd.h>
 
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool done = false;
 
class Generator
{
    private:
        int num, max;
    public:
        Generator( int mx )
        {
            num = 0;
            max = mx;
        }
        int nextNumber()
        {
            //sleep(1);
            return num++;
        }
        bool isEnd()
        {
            return num == max;
        }
};
 
class ThreadProducer
{
    private:
        std::thread thread;
        Generator *gen;
        const int id;
 
        void function()
        {
            while(!gen->isEnd())
            {
                int current = gen->nextNumber();
                // Вынесем подготовку числа из блокировки
                // producing current
 
                std::unique_lock<std::mutex> lock(m);
                produced_nums.push(current);
                cond_var.notify_all();
            }
 
            std::unique_lock<std::mutex> lock(m);
            done = true;
            cond_var.notify_all();
        }
    public:
        ThreadProducer( int id0, Generator *gn )
            : thread( &ThreadProducer::function, this ), gen( gn ), id( id0 )
        {
        }
        void start()
        {
            thread.join();
        }
};
 
class ThreadConsumer
{
    private:
        std::thread thread;
        const int id;
 
        bool get_number(int & num)
        {
            if(!produced_nums.empty())
            {
                num = produced_nums.front();
                produced_nums.pop();
                return true;
            }
            return false;
        }
 
        void function()
        {
            for(bool isExit = false; !isExit; )
            {
                int num = 0;
                bool ok = false;
                {
                    std::unique_lock<std::mutex> lock(m);
                    while(!(ok = get_number(num)) && !done)
                    {
                        cond_var.wait(lock);
                    }
                    isExit = !ok && done;
                }
                // Вынесем обработку из блокировки
                if(ok)
                {
                    //consuming num
                }
            }
        }
 
    public:
        ThreadConsumer( int id0 )
            : thread( &ThreadConsumer::function, this ), id( id0 )
        {
        }
        void start()
        {
            thread.join();
        }
};
 
int main()
{
    Generator generator( 35 );
 
    ThreadProducer p( 1, &generator );
    ThreadConsumer c1( 2 );
    ThreadConsumer c2( 3 );
 
 
    p.start();
    c1.start();
    c2.start();
    return 0;
}


Добавлено через 2 минуты
Цитата Сообщение от DiffEreD Посмотреть сообщение
while (!done || !produced_nums.empty())
А где у тебя гарантия, что эта проверка будет атомарна?
1
0 / 0 / 0
Регистрация: 20.04.2014
Сообщений: 11
15.09.2014, 20:36  [ТС]
Toshkarik, насчет detach еще буду экспериментировать.
DrOffset, спасибо. Вроде, то, что нужно!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
15.09.2014, 20:36
Помогаю со студенческими работами здесь

Программа производитель/потребитель
По книге Джонсон М. Харт &quot;Системное программирование в среде Windows&quot; есть пример этой программы, но он написан на C. Возникла проблема...

Производитель-Потребитель c собственным Монитором на мьютексах
Доброго времени суток! Решил значит изучить и разобраться в теме многопоточности и синхронизации процессов. В качестве очередного...

Алгоритм «производитель-потребитель» с использованием механизма семафоров
Реализовать алгоритм «производитель-потребитель» с использованием механизма семафоров. В качестве информации использовать строку текста....

Паттерн и задача Производитель/Потребитель (Produser/Consumer)
Хотелось бы понять, сам паттерн и задача это разные вещи? Или же это одно и тоже подразумевается? Хотелось бы какого-то содержательного...

Непонятки в Java. Chain method call. Thread.start() vs Thread.run()
Ребят, кто знает подскажите, изучаю Java уже 4 месяца, а до меня все не доходит вот к примеру такая запись, ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! в-строка - входное арифметическое выражение в инфиксной(обычной). . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru