![]() |
|
|
![]()
|
|
| JanryMayers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
Здрастье всем!
При решении определённой задачи возник, вопрос необходимо ли использовать mutex, если да то можете объяснить как будет работать программа с ним и без него? Задача: Основной поток запускает x вспомогательных, бесконечно добавляющих в некий контейнер свой элемент, потоков с некоторой изменяющейся задержкой. При этом он удаляет самый старый элемент в случае, если тот был добавлен другим потоком или если количество элементов в контейнере >Y (вот эта часть условия не ясна до конца). вот кусок кода
подскажите что нужно добавить в метод run? Это сообщение отредактировал(а) JanryMayers - 24.1.2011, 01:38 |
|||
|
||||
| borisbn |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
А где же ?
Для синхронизации между потоками в твоём случае я бы передавал в потоки не просто указатель на list, а на класс-наследник от list, который бы включал в себя ещё 2 метода - lock и unlock, а также private-член mutex. Тогда run() выглядел бы след.образом
Ну, а что должны делать ф-ции lock/unlock - думаю понятно. И ещё. Правильнее было бы написать конструктор так:
Ну, и раз уж пошла такая пьянка ... Я бы передавал не указатель, а ссылку на list -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||||
|
|||||||
| JanryMayers |
|
||||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
Спасибо, borisbn. Добавил бы те в репутацию, но постов малавата).
То есть получается mutex должен быть один единственный на все потоки. А какое у него должно быть начальное значение? И на счет функций lock/unlock:
я правильно мысль уловил? ...
почему? объясни, приведи пример) у мя щас выглядит так
и ещё варнинг warning C4355: 'this' : used in base member initializer list на m_thread( new boost::thread(boost::bind(&mThread::run, this)) ); Это сообщение отредактировал(а) JanryMayers - 24.1.2011, 11:58 |
||||||
|
|||||||
| azesmcar |
|
||||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
да. какое есть. конструктор по умолчанию все сделает. нет, классы scoped_lock, unique_lock, shared_lock... и так далее нужны для безопасности исключений. В частности scoped_lock заблокирует мьютекс в конструкторе и разблокирует в деструкторе, т.е.
эффект этой функции - 0! и еще..надо стараться блокировать как можно меньший участок кода. В частности, если код выглядет вот так то смысл использования потоков мне не совсем понятен, все равно все выполняется последовательно. Добавлено через 1 минуту и 51 секунду да, и тема тут не совсем в правильном разделе, попрошу ка я модераторов перенести ее в "Общие Вопросы". |
||||
|
|||||
| borisbn |
|
||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
просто мне ссылки больше нравятся. Ты не сможешь передать нулевой указатель (ссылки на 0 не бывает) и тебе, соответственно, не нужно всё время проверять if ( ptr != 0 ) { ptr-> ...
полностью на 100% согласен. просто в коде, представленном ТС, по другому никак. Плюс его программа, скорее всего, либо для обучения потокам и мьютексам, либо она гораздо больше и сложнее, а в том коде lock'ать необходимо, т.к. там front(), size(), pop_front() и push_back() идут непосредственно др.за др.
если это - и вся программа, то да, никакого смысла. посмотри у boost::mutex должны быть ф-ции типа lock/unlock. и ещё, в данном конкретном случае модификатор mutable IMHO бессмысленный, тем более, что ф-ции твоего класса Case не константные -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||||
|
|||||||
| JanryMayers |
|
||||||||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
теперь правильно?
задача у мя такая.
тогда лучше в этом куске кода каждое обращение к Case обработать mutex'ом
если у мя пустой список как я могу от него взять первый элемент?!! Это сообщение отредактировал(а) JanryMayers - 24.1.2011, 16:30 |
||||||||||
|
|||||||||||
| borisbn |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
ага
у тебя и так идёт обращение в каждой строке:
-------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||
|
|||||
| JanryMayers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
все таки странное условие, если я его правильно понял то
контейнер будет всегда состоять из одного элемента? О_о а то и вообще пустой Это сообщение отредактировал(а) JanryMayers - 24.1.2011, 17:51 |
|||
|
||||
| borisbn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
задание то тебе ставили - тебе и разбираться
если у первого потока задержка 10 сек, а второго одна, и они кладут элементы "1" и "2" соответственно, то в контейнере будет много 2-ек и мало единиц ( или вообще единиц не будет) и ещё. почему у тебя добавление элемента по else от удаления? Насколько я понял должно быть ЕСЛИ НУЖНО УДАЛИТЬ { УДАЛИТЬ; } ДОБАВИТЬ; -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
|||
|
||||
| azesmcar |
|
|||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
Мьютексом ничего не обрабатывается. Вкратце опишу работу мьютексов. Мьютекс - объект, имеющий минимум 2 функции - lock() и unlock(). Мьютекс может быть заблокирован одним потоком только один раз (есть и рекурсивные мьютексы, но это другой вопрос). Если мьютекс заблокирован одним потоком, то другой поток при попытке блокировке будет ждать, пока первый его не разблокирует. Таким образом мьютексы обеспечивают последовательность выполнения в параллельном мире. Т.е. часть своей функции ты можешь выполнить НЕ параллельно, а последовательно. Это значит, что эту часть кода (ту, что находиться между lock() и unlock() может выполнить одновременно лишь один поток. Следовательно, если вся функция находиться в критической секции, то и смысла использовать потоки нет, с тем же успехом эта функция может быть вызвана в цикле (вру, не с тем же, циклом будет оптимальнее). Надеюсь понятно описал. В принципе да, но 1. от std::list наследовать не стоит, он для этого не предназначен. 2. зачем нужны функции lock() и unlock()? класс (раз уж он потокобезопасен) сам должен понимать когда нужно блокировать мьютекс а когда разблокировать, от пользователя это должно быть скрыто. Это сообщение отредактировал(а) azesmcar - 24.1.2011, 22:37 |
|||
|
||||
| JanryMayers |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
спасибо за описание
а что посоветуете вместо std::list?? или его просто использовать в объект класса Case
вот такой код вроде работает как нужно. Конфликтов вроде нет. только при вводе с клавиатуры при работе потоков, нужно немного ждать, что бы они завершились. Думаю в этом нет ничего страшного. Это сообщение отредактировал(а) JanryMayers - 25.1.2011, 03:28 |
||||
|
|||||
| azesmcar |
|
|||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
Вместо list - ничего, list хорош, но вместо наследования могу посоветовать композицию. Вообще если браться за задачу правильно, то чтобы сделать лист потокобезопасным его нужно написать самому (можно и на основе стандартного, но попотеть придется). Тогда это позволит блокировать минимум кода, приведу пример. Список (std::list) - это структура, которая имеет ссылки на предыдущий и следующий элемент previous_node <-- node --> next_node каждая структура к тому же хранит значение. Сейчас, чтобы добавить элемент в список ты блокируешь весь список, выбора у тебя нет, хотя это тебе и не нужно. На самом деле, если ты добавляешь элемент в конец списка, другие потоки могут спокойно читать, удалять и добавлять в начало, но в случае полного блокирования этого не будет. Можно решить этот вопрос, если к примеру создавать мьютекс для каждого элемента (накладно, но и тут есть решение) и при работе с конкретным элементом блокировать только его, и его соседей. Это просто пример. если между lock и unlock выскочит исключение будет deadlock. Используй boost::scoped_lock. Это сообщение отредактировал(а) azesmcar - 25.1.2011, 08:03 |
|||
|
||||
| borisbn |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
в данном случае у тебя вообще неправильно должно работать, т.к. локируешь ты ДО цикла, а разлокируешь ВНУТРИ. Т.е. если придерживаться этого варианта, а не того, что советует azesmcar (кстати - правильного, но более тяжеловесного), то должно быть как-то так
Это сообщение отредактировал(а) borisbn - 25.1.2011, 10:04 -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||
|
|||||
| JanryMayers |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
её что нужно рендомить?... если да, то в каком диапозоне, лучше всего?
и что делать с этим this? он у мя варнинг сыпет warning C4355: 'this' : used in base member initializer list Это сообщение отредактировал(а) JanryMayers - 25.1.2011, 10:21 |
||||
|
|||||
| borisbn |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
повторю что означает фраза в задании, которое тебе ставили - я не знаю по поводу warning'a - вообще-то от них необходимо избавляться, но в данном конкретном случае его (C4355) можно отключить, т.к. в стандарте сказано:
а boost::bind 100% не будет "refer to the object" being они initialized или не being -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
|||
|
||||
| JanryMayers |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
вообщем остановился на таком варианте что скажите?
а вот класс с мьютексом
Это сообщение отредактировал(а) JanryMayers - 26.1.2011, 12:45 |
||||
|
|||||
| azesmcar |
|
|||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
JanryMayers
Первое, что заметил. Это ошибка, так нельзя. Да, в обычной ситуации функции front() и pop_front() лучше разделять, так-как они выполняют две задачи, к тому же сделать функцию, выполняющую более одной задачи строго-безопасной в отношении исключений довольно сложно. Но это другой случай. В данный момент перед тобой стоит задача получения элемента в многопотоной среде, с таким раскладом ты можешь получить один элемент с помощью функции front(), потом вытащить элемент с помощью функции pop_front(), но нет никакой гарантии, что ты вытащил именно тот элемент, который получил до этого, так-как между двумя вызовами этих функций другой поток может вставить значение в список и ты удалишь этот элемент даже не зная о нем. Функция pop_front() потокобезопасного списка должна возвращать значение, которое она вытащила. Если нужна строгая безопасность исключений (хотя сомневаюсь) возвращай shared_ptr. |
|||
|
||||
| borisbn |
|
||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 4875 Регистрация: 6.2.2010 Где: Ростов-на-Дону Репутация: 48 Всего: 135 |
и ещё. Ты проверяешь, например в первом потоке
потом второй поток может влезть и удалить последний элемент, а потом первый поток будет делать
первое, что приходит в голову, это весь код "бизнесс-логики" засунуть в класс Case и защитить его mutex'ом
а код потока станет таким
это мало чем отличается от варианта, где lock вызывается в потоке в самом начале, а unlock в конце, зато все потокобезопасные вещи инкапсулированы от пользователя. вариант, конечно, так себе, но всё должно работать... -------------------- Женщины отличаются от программистов тем, что у них чары состоят из стрингов |
||||||||
|
|||||||||
| JanryMayers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
понятно
я вот нашел такую вещь SharedLockable Concept void lock_shared() bool try_lock_shared() bool timed_lock_shared(boost::system_time const& abs_time) void unlock_shared() тут есть и тайм лок можно использовать вместо sleep? а также возможно написать mThread::run(), используя try/catch? |
|||
|
||||
| azesmcar |
|
|||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
||||
|
||||
| JanryMayers |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
Условие задачи такое
хотел изменяющуюся задержку реализовать sleep и mt19937 генератором... , но думаю есть способ по правильнее, чем этот
почему? может я тебя не правильно понял, но вот тут написано что какое то отношение он все таки имеет, по крайней мере функция time_lock_shared |
||||
|
|||||
| azesmcar |
|
||||||
![]() uploading... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 6291 Регистрация: 12.11.2004 Где: Армения Репутация: 3 Всего: 211 |
Ну "какое-то" далекое отношение, по сути shared не для этого ввели, а для shared ownership-а, т.е. для timed_lock-а есть TimedLockable. http://www.boost.org/doc/libs/1_32_0/doc/h...epts.TimedMutex. Но все равно, это не то, что тебе нужно.
что такое "с некоторой изменяющейся задержкой"? Мне эта часть непонятна
random-ом что ли? хотя в любом случае это sleep. |
||||||
|
|||||||
| JanryMayers |
|
||||||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 11.6.2009 Где: Украина, г. Киев Репутация: нет Всего: нет |
да рендом. я его(sleep) так написал
правда в строчке
ошибка, над исправлением которой щас работаю.., но в целом приблизительно так будет выглядеть. в этом классе
говорят, что нельзя выдавать указатель на данные под mutex'ом в этой строчке
какой выход из такой ситуации? Это сообщение отредактировал(а) JanryMayers - 30.1.2011, 18:49 |
||||||||
|
|||||||||
![]()
|
| Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets" | |
|
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |