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

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

05.04.2021, 20:16. Показов 12790. Ответов 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
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 20:41
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от JeyCi Посмотреть сообщение
может и легче так... инача лок/анлок на каждом шаге loop - тоже больно как-то для performance
Тут вообще говорить о perfomance не приходится, пример синтетический.
Если формирование сообщения в одном потоке и его обработка в другом - трудоёмкие задачи в сравнении с передачей, то параллельная обработка выиграет в производительности, блокировки не сильно повлияют (если не удерживать на время выполнения задач).
Ну а если 500 интов "запушить" и потом "запопать", то и потоки не нужны.
Ваша изначальная задача в этом примере просто передать 500 товаров другому потоку? Очередь - это просто контейнер?
Цитата Сообщение от zayats80888 Посмотреть сообщение
Ваш вариант с минимумом правок
Я забыл там bDone сбрасывать в конце основного цикла consumer
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 20:45  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
Я забыл там bDone сбрасывать в конце основного цикла consumer
заменила на bElementDone= 1 штука (в моём тестовом коде),
это не тот done, который в окончании всего цикла producer'a, вы, наверно, хотели сказать
ладно, завтра продолжу
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 20:59
Цитата Сообщение от JeyCi Посмотреть сообщение
это не тот done, который в окончании всего цикла producer'a, вы, наверно, хотели сказать
Нет, просто забыл добавить строчку bDone = false; после забора товаров (ничего больше удалять/добавлять не надо)

А вообще вам уже говорили, что этот флаг не нужен, есть empty().
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 21:03  [ТС]
да и кстати, вы правы, мой декремент не отрабатывает ВООБЩЕ
под каким углом (СВОИМ) не посмотрю

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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 
using namespace std;
 
 
int main() {
    int c = 0;
    volatile bool done = false;
    queue<int> goods;
    volatile bool bElementDone=false;
    mutex m;
    std::condition_variable cv;
 
    thread producer([&]() {               
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);                   
            goods.push(i);
            c++;
            bElementDone=true;
            cv.notify_one();
        }
        {
        std::lock_guard<mutex> lock(m);
        done = true;
        }
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
        //while (!done) {
            while (!done ) {                          
                if (!goods.empty()) {
                    goods.pop();
                    c--;
                }
                while (!bElementDone ) cv.wait(lock, [&]{return bElementDone=false;}); 
                
            }
        //}
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}

не получится же всё время на подсказках

Добавлено через 50 секунд
Цитата Сообщение от zayats80888 Посмотреть сообщение
этот флаг не нужен
но не понятно, как он нарушает логику... если сам её придерживается
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 21:17
Цитата Сообщение от JeyCi Посмотреть сообщение
да и кстати, вы правы, мой декремент не отрабатывает ВООБЩЕ
Цитата Сообщение от JeyCi Посмотреть сообщение
while (!done )
Что если producer уже звершил работу? Работа consumer закончится даже не начавшись(что у вас и происходит, иначе бы consumer завис, см. далее).

Цитата Сообщение от JeyCi Посмотреть сообщение
while (!bElementDone ) cv.wait(lock, [&]{return bElementDone=false;});
cv.wait(lock, [&]{return bElementDone=false;} это очень примерно следующее:
C++
1
2
3
4
5
while(true) {
  bElementDone=false;
  if (bElementDone == true) break;
  cv.wait(lock);
}
Это ожидание покинуть не возможно.

Подставляем в ваше выражение:
C++
1
2
3
4
5
6
while (!bElementDone ) {
  while(true) {
    bElementDone=false;
    if (bElementDone == true) break;
    cv.wait(lock);
}
Просто у вас до этого даже дело не доходит.
1
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 21:20
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
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
int main()
{
    volatile bool stop = false;
    int c = 0;
    queue<int> goods;
 
    mutex m;
    std::condition_variable cv;
 
    thread producer([&]() 
    {
        for (int i = 0; i < 500; ++i) 
        {
            std::lock_guard<mutex> lock(m);
            goods.push(i);
            c++;
            cv.notify_one();
        }
 
    m.lock();
    stop = true;
    m.unlock();
    cv.notify_all();
 
    });
 
    thread consumer([&]() 
    {
        auto wait = [&]() -> std::optional<int>
        {
            std::unique_lock<mutex> lock(m);
            while (goods.empty())
            {
                if (stop)
                    return std::nullopt;
 
                cv.wait(lock);
            }
 
            auto n = goods.front();
            goods.pop();
            c--;
            return n;       
        };
 
        for (;;)
        {
            auto val = wait();
            if (!val)
                break;
 
            std::cout << (*val + 1) << std::endl;
        }
    });
 
    producer.join();
    
    consumer.join();
    cout << "Net: " << c << endl;
}
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 21:33  [ТС]
zayats80888, убедили... ставлю
C++
1
2
                while (!bElementDone ) cv.wait(lock, [&]{return bElementDone;}); 
                bElementDone=false;
декремент начинает очень редко срабатывать, перестаю виснуть, предчуствую, что у меня не везде соблюдается синхронизация флагов и int c...- хотя я же под локом std::unique_lock<mutex> lock(m); в consumer'e...
- продолжаю править дальше...
спасибо за вскрытие грубой ошибки...
oleg-m1973, и за ваш вариант спасибо
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 21:43
Лучший ответ Сообщение было отмечено JeyCi как решение

Решение

Цитата Сообщение от JeyCi Посмотреть сообщение
ставлю
Либо cv.wait(lock, [&]{return bElementDone;}); либо while (!bElementDone ) cv.wait(lock);, а то масло маслянное получается.
Цитата Сообщение от JeyCi Посмотреть сообщение
декремент начинает очень редко срабатывать
И об этом я тоже написал, while (!done ) вклинится, например, после первых двух элементов, вы их вытащите, пойдёте спать, за это время producer накидает остальных, выставит флаг done, вы проснётесь и на следующей итерации цикла проверка done закончит работу, оставшееся вы так и не заберёте.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 21:55  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
а то масло маслянное получается.
от ложных пробуждений... имхо

Добавлено через 50 секунд
Цитата Сообщение от zayats80888 Посмотреть сообщение
вы проснётесь и на следующей итерации цикла проверка done закончит работу, оставшееся вы так и не заберёте.
вероятно, вы правы...
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 21:58
Цитата Сообщение от JeyCi Посмотреть сообщение
от ложных пробуждений... имхо
Забудь уже об этих "ложных пробуждениях". Проектируй свой код в расчёте на то, что каждое пробуждение ложное.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 21:59
Цитата Сообщение от JeyCi Посмотреть сообщение
от ложных пробуждений... имхо
Они и так учитываются предикатом или условием цикла ожидания!
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 22:06  [ТС]
мы добили его - моим ходом логической мысли... хоть как-то... ok! декремент выводит в 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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <chrono>
#include <queue>
 #include <atomic> 
 
using namespace std;
 
 
int main() {
    int c = 0;
    volatile std::atomic_bool  done = false;
    queue<int> goods;
    volatile bool bElementDone=false;
    mutex m;
    std::condition_variable cv;
 
    thread producer([&]() {               
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);                   
            goods.push(i);
            c++;
            bElementDone=true;
            cv.notify_one();
        }
        {
        std::lock_guard<mutex> lock(m);
        done = true;
        }
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
            while (!goods.empty()) {                          
                goods.pop();
                c--;
                if (!done) {
                    // NOT while (!bElementDone ) cv.wait(lock, [&]{return bElementDone;});  
                    // while (!bElementDone ) cv.wait(lock);
                    cv.wait(lock, [&]{return bElementDone;});               
                    bElementDone=false; 
                }
            }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}
всем спасибо
... только в правильности объявлений не совсем уверена
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 22:12
Цитата Сообщение от JeyCi Посмотреть сообщение
while (!goods.empty())
Подумайте, а что если consumer запустится раньше producer.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 22:13
Цитата Сообщение от JeyCi Посмотреть сообщение
мы добили его - моим ходом логической мысли... хоть как-то ok!
Нет, не добили
Цитата Сообщение от JeyCi Посмотреть сообщение
volatile bool bElementDone=false;
Это вообще не нужно
Цитата Сообщение от JeyCi Посмотреть сообщение
{
        std::lock_guard<mutex> lock(m);
        done = true;
        }
После этого нужно сделать notify_one/all
И, собственно, получится тот код, который я тебе показывал, только хуже.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
07.04.2021, 22:16  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
только хуже.
чем?
помимо того, что блокировку можно убрать в producer перед done=true (если его объявить atomic_bool)
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
07.04.2021, 22:19
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
После этого нужно сделать notify_one/all
И прверять флаг в предикате, иначе можно зависнуть, если вытащили последний элемент перед установкой флага в продюсере.
Это тот же косяк, о котором я говорил в 33 посте про свою портянку.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
07.04.2021, 22:23
Цитата Сообщение от JeyCi Посмотреть сообщение
чем?
Тем, что это примитивная задача. У неё правильных решений - по пальцам пересчитать (а вот неправильных - тьма). Одно из них я тебе показал.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
08.04.2021, 08:11  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Это вообще не нужно
- да, хотели понять логику, чтобы убрать всё лишнее... чтобы логика стала стройной
ХОТЯ
просто думала, что если notify'ить после загрузки каждого элемента bElementDone - то consumer УЖЕ будет обрабатывать имеющиеся в очереди элементы, хоть она ещё и не full... т.е. всё-таки параллельно... по FIFO
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
После этого нужно сделать notify_one/all
-- да, забыла уведомить 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
#include <iostream>
#include <thread>
#include <condition_variable>
#include  <mutex>
#include <queue>
#include <atomic> 
 
using namespace std;
 
int main() {
    int c = 0;
    volatile std::atomic_bool  done = false;
    queue<int> goods;
    mutex m;
    std::condition_variable cv;
 
    thread producer([&]() {               
        for (int i = 0; i < 500; ++i) { 
            std::lock_guard<mutex> lock(m);                   
            goods.push(i);
            c++;
        }
        done = true;
        cv.notify_one();
    });
 
    thread consumer([&]() {
        std::unique_lock<mutex> lock(m);
            while (!goods.empty()) {                          
               goods.pop();
               c--;
               if (!done) cv.wait(lock, [&]{return done;});              
            }
    });
 
    producer.join();
    consumer.join();
    cout << "Net: " << c << endl;
}

НО т.к.
Цитата Сообщение от DrOffset Посмотреть сообщение
нельзя освобождать блокировку перед уведомлением.
- то блокировка, устанавливаеиая в for-loop'е, смотрится как-то не очень... НО т.к. флаг переделала на atomic_bool - то очень даже терпимо...
p.s.
но выходить из producer'a в consumer будет только после загрузки всей очереди - т.е. опять же producer блокирован на всё время своей работы - только блокировка рывками лочится/разлочивается... (на каждом loop)...
единственное преимущество такого подхода, вероятно, в том, что на время загрузки очереди ничего не будет виснуть?.. - в смысле Event-loop самого приложения...
p.p.s
- остальные нюансы - касаются вопросов скорости - чтобы определиться с предпочтениями по тому или иному коду этой ветки
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
08.04.2021, 10:00
Цитата Сообщение от JeyCi Посмотреть сообщение
-- да, забыла уведомить consumer'а
Кликните здесь для просмотра всего текста
Ужасно. Раньше и то было лучше.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,524
08.04.2021, 10:48  [ТС]
конечно, ужасно... ведь все советы применила с этой ветки...
а по делу начинают появляться только ваши эмоции...
мне совет от DrOffset кажется самым валидным
Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что нельзя освобождать блокировку перед уведомлением.
что в принципе большими буквами в комментах было ещё здесь ... спасибо DrOffset'у за напоминание...
ВЫВОД: не старайтесь казаться умнее самой логики - опУститесь до негативных эмоций, которые даже объяснениям не поддаются... потеряете дар речи
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
08.04.2021, 10:48
Помогаю со студенческими работами здесь

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

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Символические и жёсткие ссылки в Linux.
algri14 15.03.2026
Существует два типа ссылок — символические и жёсткие. Ссылка в Linux — это дополнительная запись в каталоге, которая может указывать либо на inode «файла-ИСТОЧНИКА», тогда это будет «жёсткая. . .
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
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
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru