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

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

05.04.2021, 20:16. Показов 13313. Ответов 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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
264 / 153 / 33
Регистрация: 29.06.2019
Сообщений: 1,547
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
Ответ Создать тему
Новые блоги и статьи
Рефакторинг программы уравнивания.
Massaraksh7 26.05.2026
Пример по предыдущей записи в блоге. Но, надо заметить, что, во-первых, там оптимизация не только математики, но и работы с базой данных, и с графами, а во-вторых, это ещё не всё.
Использование TThread в Lazarus для математических вычислений.
Massaraksh7 25.05.2026
Производя рефакторинг своих программ на предмет ускорения их работы, обратил внимание на такой аспект, как сокращение времени матвычислений. Дело в том, что приходится работать с большими матрицами. . .
Модель здравосохранения 18. Чем здоровее работник, тем быстрее выгорает
anaschu 24.05.2026
Имитационная модель корпоративного здравоохранения: что показывает математика Сегодня в модели рабочего коллектива на AnyLogic появились три новые механики — выгорание через накопленную усталость,. . .
Модель здравосохранения 17. Планы на выгорание
anaschu 23.05.2026
Вот конкретная схема реализации: В классе Работник добавить: накопленнаяУсталость — растёт каждый час работы, снижается в перерывы и болезни коэффициентПрезентеизма — снижает продуктивность. . .
Изменение цветов в палитре gif файла aka фавикона
russiannick 23.05.2026
Изменение цветов в палитре gif файла, юзаемого как фавиконка в составе html-файла, помещенная в base64, средствами нативного Java Script, навеянное сном в майский день. Для работы необходим браузер,. . .
Модель здравосохранения 16. Слишком хорошие и здоровые сотрудники уходят, недовольные зарплатой
anaschu 23.05.2026
Отладка увольнений и настройка производительности Сегодня во второй половине дня разобрались с механикой увольнений и настроили коэффициент сложности заданий. Вот что было сделано. . . .
Как я стал коммунистом))) Модель сохранения здоровья сотрудников, запись блога номер 15
anaschu 23.05.2026
Внезапно хорошее здоровье сотрудников не нужно капиталистам?))
Модель здравоСохранения 15. Как мы чинили AnyLogic модель рабочего коллектива: сочленение диаграммы состояний болезней и поломок в ресурспул
anaschu 23.05.2026
Как мы чинили AnyLogic модель рабочего коллектива Сегодня разобрались с пятью багами, из-за которых модель либо падала с ошибкой, либо давала совершенно бессмысленные результаты. Каждый баг был. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru