Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.71/58: Рейтинг темы: голосов - 58, средняя оценка - 4.71
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524

Потоко-безопасная Очередь

05.04.2021, 20:16. Показов 12779. Ответов 106
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
... вырисовалась тема отсюда
Цитата Сообщение от zayats80888 Посмотреть сообщение
Хотя не сложно написать такую очередь(с раздельной блокировкой для "хвоста" и "головы") самостоятельно.
вот выполнила последнюю задачку отсюда - но не знаю, может лучше shared_mutex вместо просто mutex? правда на него unique_lock<shared_mutex> не ставится...
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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 
using namespace std;
 
  bool bDone;
  mutex m;
  std::condition_variable cv;
 
int main() {
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    thread producer([&]() {
        std::lock_guard<mutex> lock(m);
        for (int i = 0; i < 500; ++i) {            
            goods.push(i);
            c++;
            cv.notify_one();
        }
 
        done = true;
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        while (!done) {
            while (!goods.empty()) {
                goods.pop();
                c--;
                while (!bDone) cv.wait(lock);
            }
        }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}
тут же не раздельная блокировка? - это FIFO, насколько понимаю...
а раздельная - вы, наверно, имеете ввиду для LIFO... наверно лучше на list выполнять?
sorry, что много вопросов - стою на распутье - даже в отдельную тему вынесла
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
05.04.2021, 20:16
Ответы с готовыми решениями:

Потоко-независимая очередь записывает 2е команды в одну ячейку. Почему ?
Доброго времени суток. Написал 2а приложения общяющихся между собой по TCP. Одно является сервером(планшет), второе клиент(windows). ...

Потоко-безопасный ObservableCollection с AddRange
Вообщем, я заполняю в нескольких потоках массив. на данный момент использую &quot;List&lt;ExpandoObject&gt; Вывод&quot; из-за...

Является ли boost::asio::tcp::acceptor потоко-безопасным ?
Мне сложно понять смысл того что написано в документации: ...

106
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,816
07.04.2021, 17:15
Студворк — интернет-сервис помощи студентам
oleg-m1973, да, согласен, тут я не прав. Хотя это и не повредит.

Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Зачем этот цикл?
Я бы даже сказал "зачем там все эти циклы?"
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 17:15
Цитата Сообщение от JeyCi Посмотреть сообщение
работает нестабильно - иногда зависает, ничего не выведя
Ваш consumer странно написан. Он должен завершать работу только когда выставлен флаг done и очередь пуста.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 18:13  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
volatile bool bDone;
- для компилятора...
всё время хочется ещё и atomic сделать для процессора...
но во всех прмерах почему-то без atomic?
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Зачем этот цикл?
правильнее так
C++
1
while (!bDone) cv.wait(lock;[=]{return bDone=true;});
- чтобы избежать ложных пробуждений... (другого слово быстро не нашла bDone)
ой, точно - поставила в producer перед notify - bDone=true; - вроде стал стабилен...
но можно и wait не-перегруженный лямбдой, как вы здесь делали

Добавлено через 4 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
Ваш consumer странно написан. Он должен завершать работу только когда выставлен флаг done и очередь пуста.
та ведь и есть
C++
1
2
        while (!done) {
            while (!goods.empty()) {
это др. done
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 18:16
Цитата Сообщение от JeyCi Посмотреть сообщение
правильнее так
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
    mutex m;
    std::condition_variable cv;
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    thread producer([&]() {        
        for (int i = 0; i < 500; ++i) { 
            {
                std::lock_guard<mutex> lock(m);           
                goods.push(i);
                c++;
            }
            cv.notify_one();
        }
        std::lock_guard<mutex> lock(m);
        done = true; // <- нужна блокировка(атомарность как минимум)
    });
 
    thread consumer([&]() {
        for(;!(done && goods.empty());) { // завершаем только когда очередь пуста и пополнений больше не будет
            std::unique_lock<mutex> lock(m);    
            cv.wait(lock, [&goods]{ return !goods.empty(); }); // тут только ожидание уведомления об очередном сообщении в очереди
            c--;
            goods.pop();
        }
    });
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 18:30  [ТС]
zayats80888, ваш вариант выдаёт Net=0 ... (win32 gcc 9.3)
кстати мой с моими правками всё ещё не стабилен... смахивает на deadlock? симптомы, как и прежде
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 18:33
Цитата Сообщение от JeyCi Посмотреть сообщение
ваш вариант выдаёт Net=0
Ну а что он должен выдавать?
Цитата Сообщение от JeyCi Посмотреть сообщение
кстати мой с моими правками всё ещё не стабилен...
Покажите.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 18:34  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Ну а что он должен выдавать?
Net=500
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 18:37
Цитата Сообщение от JeyCi Посмотреть сообщение
Net=500
Каким образом? И что это должно значить? Уберите декремент c - будет выдавать 500...
Или перенесите инкремент в сonsumer...
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 18:41  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Покажите.
я просто воспользовалась советом от DrOffset, и подправила то, что от oleg-m1973, - отпостила в #23
всё
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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 
using namespace std;
 
  volatile bool bDone;
  mutex m;
  std::condition_variable cv;
 
int main() {
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    thread producer([&]() {               
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);                   
            goods.push(i);
            c++;
            bDone=true;
            cv.notify_one();
        }
        std::lock_guard<mutex> lock(m);
        done = true;
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        while (!done) {
            while (!goods.empty()) {
                goods.pop();
                c--;
                while (!bDone) cv.wait(lock, [=]{return bDone=true;});
            }
        }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}


Добавлено через 2 минуты
я кстати согласна с вашими комментами по вашему коду...
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 18:47
У меня вопросы к вашему коду:
1) Зачем флаг bDone, если есть метод empty?
2) Зачем декремент с в consumer, если вы ожидаете 500?
3) Что это должно означать и почему присвоение в теле лямбды, да ещё и захваченному копированием объекту
Цитата Сообщение от JeyCi Посмотреть сообщение
while (!bDone) cv.wait(lock, [=]{return bDone=true;});
??
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 18:54  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Уберите декремент c - будет выдавать 500...
значит в моём коде всё-таки прорывается "ложное пробуждение"?
не deadlock

Добавлено через 3 минуты
вобщем, всем спасибо!.. - тормозит i'net (сбивает с мысли, пока пост доходит до форума) - ещё раз проверю и оттестирую все мысли (и свои и чужие)... в любом случае всем спасибо - все мысли уловила (даже быстрее, чем моё соединение с i'net сейчас)

Добавлено через 1 минуту
только вопрос этого поста остался вопросом... - подумаю ещё

Добавлено через 1 минуту
кстати
1) написала, что согласна
2) написала, что согласна
3) от "ложных пробуждений" - согласна, по ссылке надо захватить
0
зомбяк
 Аватар для TRam_
1585 / 1219 / 345
Регистрация: 14.05.2017
Сообщений: 3,940
07.04.2021, 19:16
Лучший ответ Сообщение было отмечено JeyCi как решение

Решение

Не до конца понятно, что тут в очередях предполагается сделать, но если нужно "получить однопоточное исполнение для двух потоков", можно и вот так (условие (i % 10) == 0 эмулирует накопление очереди, цикл в потребителе - её обработку...):

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
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <queue>
using namespace std;
 
int main() {
    int c = 0;
    bool done = false;
    queue<int> goods;
 
    mutex m;
    std::condition_variable cv;
    std::condition_variable cv2;
 
    thread producer([&]() {
 
        std::unique_lock<std::mutex> lk(m);
        for (int i = 0; i < 500; ++i) {
            goods.push(i);
            c++;
 
            if ((i % 10) == 0)
            {
                cv.notify_one();
                cv2.wait(lk);
            }
        }
 
        done = true;
        cv.notify_one();
        });
 
    thread consumer([&]() {
 
        std::unique_lock<std::mutex> lk(m);
        while (!done) {
            cv.wait(lk, [&done, &goods] {return (done || !goods.empty()); });
            while (!goods.empty())
            {
                goods.pop();
                c--;
            }
            cv2.notify_one();
        }
        });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 19:24
Цитата Сообщение от JeyCi Посмотреть сообщение
тормозит i'net
Это форум лагает.

Кстати, я там в коде не учел один момент, из-за "отпускания" блокировки в producer перед выставлением флага done, consumer может зависнуть в ожидании.
Т.е. флаг завершения нужно ставить внутри цикла producer или проверять его в ожидании на condition_variable.

Цитата Сообщение от TRam_ Посмотреть сообщение
Не до конца понятно, что тут в очередях предполагается сделать
Если очередь, то предполагается использовать её как канал передачи сообщений между потоками.
Если же очередь сама является сообщением, да ещё и одноразовым(как в изначальном варианте), то и смысла в потоках особого нет.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 19:33  [ТС]
и кстати, глобальнаяую переменную вроде по ссылке нельзя захватить, значит объявление перенести в main...
но с учётом того, что даже с флагом вместо проверки goods.empty() логика соблюдается - хоть и через лишнюю переменную, - всё равно не понимаю, что в моём случае даёт нестабильность (даже с [&])
просто интересно понять

Добавлено через 6 минут
Цитата Сообщение от zayats80888 Посмотреть сообщение
Если же очередь сама является сообщением, да ещё и одноразовым(как в изначальном варианте), то и смысла в потоках особого нет.
согласна - надо передавать поштучно и принимать поштучно
просто размять мозги, перейдя 1 раз между потоками, тоже не помешает
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 19:33
Цитата Сообщение от JeyCi Посмотреть сообщение
и кстати, глобальнаяую переменную вроде по ссылке нельзя захватить,
Можно. Ваши лямбды потоков так их и захватывают.
Цитата Сообщение от JeyCi Посмотреть сообщение
но с учётом того, что даже с флагом вместо проверки goods.empty() логика соблюдается - хоть и через лишнюю переменную, - всё равно не понимаю, что в моём случае даёт нестабильность (даже с [&])
Ваш вариант с минимумом правок
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    thread producer([&]() {               
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);                   
            goods.push(i);
            bDone=true;
            cv.notify_one();
        }
        std::lock_guard<mutex> lock(m);
        done = true;
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        while (true) {
            while (!bDone || !done) cv.wait(lock);
            while (!goods.empty()) {
                goods.pop();
                c++;
            }
            if (done) // это здесь на случай, если producer завершится раньше, чем стартанёт consumer
                break;
        }
    });
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 19:34  [ТС]
del
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 19:37
Цитата Сообщение от JeyCi Посмотреть сообщение
- чтобы избежать ложных пробуждений... (другого слово быстро не нашла bDone)
А что будет в случае этого "ложного пробуждения"? В нормальном коде такие фокусы как-то не нужны.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 20:10  [ТС]
ой, подправила ещё (впридачу к [&]) -- false
C++
1
while (!bDone) cv.wait(lock, [&]{return bDone=false;});
=====
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
А что будет в случае этого "ложного пробуждения"?
++1... empty() ...
oleg-m1973, мне вот тоже показалось сейчас то же самое, только под др ракурсом
Цитата Сообщение от JeyCi Посмотреть сообщение
while (!done) {
while (!goods.empty()) {
вот тут, скорее всего, и проблема моего кода, как и ответ на ваш вопрос (только вид совсем под др углом)... т.е. в моём коде - он выходит из while , наверно, если вдруг producer ещё не пропихнул новый элемент в очередь => по (!goods.empty())... а выйти из while (!done) не может, если вся очередь ещё не done...
ну, это если воспользоваться советом от zayats80888, - и блокировать в цикле...

Добавлено через 5 минут
может, TRam_ и прав, - чтобы лочить в цикле и перебрасывать фокус внимания потоков на разделяемую переменную - лучше 2 c.v. -- оно, может и легче так... инача лок/анлок на каждом шаге loop - тоже больно как-то для performance
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 20:11
Цитата Сообщение от JeyCi Посмотреть сообщение
ой, подправила ещё (впридачу к [&])
У берите эту лямбду, это же предикат. Он у вас возвращает false, т.е. не даёт возможности выйти из ожидания.
Сбрасывайте этот флаг в конце цикла и всё.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 20:11
Цитата Сообщение от JeyCi Посмотреть сообщение
++1... empty() ...
oleg-m1973, мне вот тоже показалось сейчас то же самое, только под др ракурсом
Просто проверяй на empty перед удалением элемента из списка и всё. Никакие дополнительные переменные там не нужны
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
07.04.2021, 20:11
Помогаю со студенческими работами здесь

Сформировать односвязную очередь из элементов, которые входят в очередь Q1, но не входят в очередь Q2
Составить программу обработки динамической структуры данных: сформировать односвязную очередь Q из элементов, которые входят в очередь Q1,...

Не безопасная форма
Привет, пользуюсь менеджером паролей Lastpass, и мне интересно, что такое не безопасная форма? У разработчика спрашивал, но он объяснил что...

Безопасная работа
_http://www.webpark . ru/comments.php?id=45545

Безопасная регистрация
Всем привет. Вот я собственно попытался сделать систему регистрации, в PHP пока еще не особо силен, только понемногу начинаю учится. ...

Безопасная авторизация
Здравствуйте! Есть приложение клиент, которое обращается к wcf сервису, чтобы то произвело какие то действия. Клиент написан под...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
BOINC: 22 года — и всё ещё работает
Programma_Boinc 12.03.2026
BOINC: 22 года — и всё ещё работает Дэвид Андерсон написал ретроспективу. Кратко: в 2001 году он ушёл из United Devices, где был CTO, и за несколько месяцев написал ядро BOINC — клиент, сервер,. . .
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru