![]() |
|
Модераторы: LSD, AntonSaburov |
![]()
|
|
| libertas |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 10.3.2014 Репутация: нет Всего: нет |
Всем привет!
Написал программу, где есть несколько потоков - читатели и писатели. Есть воображаемая БД. Когда читатель хочет что- нибудь прочитать, он проверяет не пишет ли писатель сейчас данные в БД. Если пишет - то читатель ожидает. Аналогично писатель - ожидает пока все читатели прочитают. Читателей может быть несколько одновременно, писатель - только один. Нужно задачку решить через семафоры, которые нужно написать самому.
Я написал семафор - Semaphore, который в зависимости от значения value проверяет - читать / писать. Я понимаю, что эти семафоры не атомарны, но задачку надо решить именно через семафоры, написанные вручную. В этом коде проиходит исключение: Exception in thread "Thread-3" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:503) at Database.startRead(MyProg.java:113) at Reader.run(MyProg.java:39) В чем может быть дело? Спасибо |
|||
|
||||
| LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Ошибка говорит о том, что метод wait() должен вызываться потоком которых захватил монитор на объект (у которого вызыватся wait()). Но это все не важно, тут есть проблемы серьезней:
1. Непонятно причем тут семафоры, когда это типичный read-write lock. 2. Реализовать семафор самостоятельно без "нативной" поддержки нельзя. Или надо использовать synchronized или готовую реализацию из java.util.concurrent. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
|||
|
||||
| Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Пожалуй рискну не согласиться. Реализовать семафор все-таки можно, но семафор нужно опрашивать на предмет разрешенности действия. А вот опроса семафора я в коде не увидел. По идее должно быть что-то вроде: Читатель семафору "Можно читать?", Семафор читателю "Можно", тогда стартует чтение. Правда при многопоточности нет гарантии, что между ответом семафора и собственно началом чтения не влезет кто-то еще. Для предотвращения такого конфликта, семафор в случае положительного ответа сначала блокирует доступ другим, а уже затем выдает ответ. Получается кривовато, но работоспособно, если читатель не забудет читать после запроса и т.д. Но в предположении приличного поведения читателей и писателей семафор сделать можно. В реальное, не учебное, приложение я бы такой семафор не включал Это сообщение отредактировал(а) Mirkes - 9.4.2014, 22:34 -------------------- Mirkes |
|||
|
||||
| libertas |
|
||||
|
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 10.3.2014 Репутация: нет Всего: нет |
Спасибо. Да согласен, именно с этим и была проблема. Плюс проблема в растановке семафоров. Вот переделанный рабочий код:
Добавлено через 2 минуты и 5 секунд Согласен.
Извините, не очень понятно как это можно сделать? |
||||
|
|||||
| LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
1. Не решается вопрос как "усыпить" поток на время ожидания захвата семафора. Можно конечно busy spin сделать, но это не очень хорошее решение в общем случае. 2. Без блокировок или CAS нельзя произвести атомарный инкремент/декремент (хватит ли одного CAS для реализации семафора я не уверен). Твой семафор работает неправильно. В случае если счетчик на нуле, и 2 потока вызовут acquire(), счетчик станет -2. Потом один поток вызовет release() счетчик станет -1 и один из потоков пробудится, что неправильно. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
|||
|
||||
| libertas |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 10.3.2014 Репутация: нет Всего: нет |
Извините, можно пояснить. Где/когда 2 моих потока будут вызывать acquire()? И где/когда один мой поток будет вызывать release()? |
|||
|
||||
| LSD |
|
||||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
У тебя там куча ошибок: 1. Операция ++ не атомарна. В многопоточной среде может давать неправильный результат. Плюс у тебя переменные не volatille потоки увидят изменения сделанные друг другом в непредсказуемый момент. 2. Операция
не атомарна. Возможна ситуация: - проверили условие оно истинно - ОС усыпила поток - другой поток поменял что-то и условие уже не выполняется - ОС разбудила первый поток и он пошел выполнять doOperation(), хотя условие уже не выполняется 3. Логические ошибки в Database у тебя в начале метода startRead() вызывается sem.P(), который поддерживает только один поток. Т.е. второй читатель будет ждать, хотя читатели должны работать паралельно. 4. Реализация самого Semaphore: - поток 1 заходит в startRead() и вызывает sem.P() и усыпляется ОС где-то в середине метода, значение value = 0 - поток 2 заходит в startRead() и вызывает sem.P() и засыпает, значение value = -1 - поток 3 заходит в startRead() и вызывает sem.P() и засыпает, значение value = -2 - поток 1 выходит из метода и вызывает sem.V(), просыпается один из потоков 2 или 3, значение value = -1 В принципе котракт не нарушен - только один поток выполняется, но странно. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
||||
|
|||||
| libertas |
|
||||||
|
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 10.3.2014 Репутация: нет Всего: нет |
Если Вы имеете в виду : readerCount++; то она защищена семафором. Если поток заснул, то другой все равно не сможет её изменить. А если про эту: ++value; то она находится в методе synchronized - следовательно может меняться только одним потоком. Так работает synchronized .
Это невозможно, потому что if (<check condition>) doOperation(); защищено synchronized семафором.
Тоже не может быть, потому что sem.P() synchronized . Есть там, конечно не точность в коде. Сейчас только увидел:
В этом участке, если читатель пройдет семафор и уснет, то другие читатель не смогут заходить в этот блок, пока не проснется этот читатель и не откроет семафор. |
||||||
|
|||||||
| LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Замечание насчет vollatile все равно остается в силе.
Все замечания про защиту монитром верны до тех пор пока у него count = 1, ты его используешь как обычный мьютекс. Проще уж сразу было делать synchronized и не мучаться. Речь не про sem.P(), а про вызывающий метод. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
|||
|
||||
| Mirkes |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 586 Регистрация: 18.8.2011 Где: Красноярск Репутация: 7 Всего: 17 |
Хорошее решение должно опираться на синхронизацию или конкуренцию (со второй не знаком пока). Я же написал, что в приличную программу я бы предложенный мной семафор не включил. "Усыпление" потока осуществляется тупо - он просится, пока не получит разрешения. Это очень расточительно по ресурсам, но осуществимо. Довольно давно под DOS мне приходилось реализовывать многозадачность. Это куча проблем, жестоко карается любая ошибка, но в принципе осуществимо. Единственное, что мне не понятно, зачем давать такое как учебную задачу. -------------------- Mirkes |
|||
|
||||
| libertas |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 29 Регистрация: 10.3.2014 Репутация: нет Всего: нет |
да, про volatile нужно почитать. Ну да тут мьютекс получается. Согласен, что проще делать быть через synchronized, просто задание было сделать именно через семафоры. Добавлено через 37 секунд
Ну да, ресурсы цпу жрет - крутится в цикле. |
|||
|
||||
| LSD |
|
||||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Это и есть busy spin, более того он иногда оправдае, например java.util.concurrent.atomic его используют. Основная проблема во втором пункте:
Я немного посмотрел - CAS хватит для реализации семафора с busy spin. -------------------- Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it. |
||||
|
|||||
![]()
|
| Правила форума "Java" | |
|
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |