Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности
|
|
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
На выходных я решил по изучать возможности стандартной библиотеки С++11. Завёл MSVC2012 и начал писать класс пула потоков с очередью заданий. В результате, в пока далеко не законченном варианте, получился примерно такой код: ThreadPool.h: Код: plaintext 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. ThreadPool.cpp: Код: plaintext 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. Для тестов использовалось консольное приложение: Код: plaintext 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. Всё работает отлично (не считая отсутствия синхронизации, в том числе при выводе в консоль, но это не законченный вариант). Но вот только при вызове каждой группы tp.addTask из консольной программы, вызов this->cvThreadAwait.notify_one(); в методе void ThreadPool::addTask(ThreadPoolTask& task, const bool& queueBegin) будит один и тот же поток! (привёл в файле картинку вывода для наглядности) Если вместо notify_one() использовать notify_all() , то, как и задумано, вызываются случайные потоки на каждое задание. Что я делаю не верно, что вызывается один и тот же поток? При этом при загрузке следующей группы заданий возможно будет использоваться другой поток, но точно так же только он один. Или может я не правильно понимаю нормальное поведение notify_one() ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.11.2013, 22:00 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighter, Потому что, глядя на функцию потока, как только какой нибудь поток получает сообщение, он уже никогда не вызывает wait() снова, таким образом не разблокируя мьютекс и не давая шанса другим потокам получить следующие сообщения. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.11.2013, 02:48 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighter, твои задания исполняются с залоченным мютексом. Код: plaintext 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. Добавление в tasks нужно защитить мютексом Код: plaintext 1. 2. 3. 4. 5. 6. 7. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.11.2013, 04:25 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
Спасибо за ответы. Видимо я не совсем понимаю принцип действия conditional_variable, раз ошибка действительно в этом. Сейчас код мне не доступен, дома проверю как будет с исправлениями. А кто-нибудь может мне коротко и доступно объяснить как работает conditional_variable, чтобы больше не возникало таких непониманий? Я читал на cplusplus.com, но видимо что-то не до конца понял..... (Я вообще впервые работаю с условными переменными в принципе) В моём понимании при вызове notify() поток должен автоматически разблокировать mutex захваченный conditional_variable , видимо нет? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.11.2013, 15:18 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighterСпасибо за ответы. Видимо я не совсем понимаю принцип действия conditional_variable, раз ошибка действительно в этом. Сейчас код мне не доступен, дома проверю как будет с исправлениями. А кто-нибудь может мне коротко и доступно объяснить как работает conditional_variable, чтобы больше не возникало таких непониманий? Я читал на cplusplus.com, но видимо что-то не до конца понял..... (Я вообще впервые работаю с условными переменными в принципе) В моём понимании при вызове notify() поток должен автоматически разблокировать mutex захваченный conditional_variable , видимо нет? Наоборот. При входе в wait нить блокируется и мютекс освобождается а по notify_... одна или все нити разблокируются и конкурируют за мютекс, захватившая его нить выходит из wait. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.11.2013, 15:45 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
Проверил код дома - само собой помогло =) А так-же большое спасибо за объяснение, кажется теперь я понимаю как это работает =) А подскажите, не слишком ли накладно получается тут работа с мьютексом? В потоке для выполнения одного задания происходят: 1. Захват мьютекса 2. Освобождение мьютекса при ожидании на условной переменной 3. Взятие мьютекса при пробуждении на условной переменной 4. Освобождение мьютекса после взятия задания из очереди 5. Обратный захват мьютекса после выполнения задания (повторение п.1 ?) Ведь на сколько я знаю работа с мьютексами очень затратна по ресурсам (хотя в данном случае наверное избавление от цикла ожидания задания даёт больший выигрыш). Может можете подсказать, есть более "правильный" вариант организации работы пула потоков с пополняющейся очередью заданий? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 11.11.2013, 19:34 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighterПроверил код дома - само собой помогло =) А так-же большое спасибо за объяснение, кажется теперь я понимаю как это работает =) А подскажите, не слишком ли накладно получается тут работа с мьютексом? В потоке для выполнения одного задания происходят: 1. Захват мьютекса 2. Освобождение мьютекса при ожидании на условной переменной 3. Взятие мьютекса при пробуждении на условной переменной 4. Освобождение мьютекса после взятия задания из очереди 5. Обратный захват мьютекса после выполнения задания (повторение п.1 ?) Ведь на сколько я знаю работа с мьютексами очень затратна по ресурсам (хотя в данном случае наверное избавление от цикла ожидания задания даёт больший выигрыш). Может можете подсказать, есть более "правильный" вариант организации работы пула потоков с пополняющейся очередью заданий? На самом деле не все так страшно. Один lock/unlock на круг. Как ты себе представляешь доступ к очереди задач без блокировок? Другое дело что есть много места для оптимизации. Например STL контейнеры не самое лучшее решение для очереди. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.11.2013, 00:29 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
locked, Так вроде 2 lock/unlock на круг о_О Те что в коде и те что происходят внутри wait , нет? Было бы интересно выслушать все замечания по поводу возможных оптимизаций =) По поводу STL - конечно изначально именно в нём и пытался потренироваться) Но почему не лучшее решение использовать STL? Что вместо, статические массивы? Тогда либо очередь фиксированной длины, либо код по управлению размером массива, аналогичный STL-евскому. + При использовании STL можно вообще шаблонное задание сделать (правда я не стал тк решил что с помошью 2х указателей переданных в обработчик можно решить любую задачу, например pThis и pMyDataStructure) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.11.2013, 12:25 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighterlocked, Так вроде 2 lock/unlock на круг о_О Если очередь пуста - зачем тогда нужен пул? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.11.2013, 12:41 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
lockedHellFighterlocked, Так вроде 2 lock/unlock на круг о_О Если очередь пуста - зачем тогда нужен пул? А как это относится к цитате? о_О Не понял вопроса... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.11.2013, 19:22 |
|
||
|
std::conditional_variable.notify_one() "будит" один и тот же поток
|
|||
|---|---|---|---|
|
#18+
HellFighter, Он имеет в виду - если вы не будете отпускать мьютекс пока обрабатываете сообщение, то только один поток будет обрабатывать сообщения, а остальные будут ждать, что делает пул потоков бесполезным. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 12.11.2013, 19:33 |
|
||
|
|

start [/forum/topic.php?fid=57&msg=38460581&tid=2019875]: |
0ms |
get settings: |
9ms |
get forum list: |
14ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
162ms |
get topic data: |
13ms |
get forum data: |
3ms |
get page messages: |
57ms |
get tp. blocked users: |
2ms |
| others: | 316ms |
| total: | 584ms |

| 0 / 0 |
