-
Пишу прогу-клиент FTP на Delphi7, используя WinAPI. Прога многопоточная. Возникла интересная трабла: переменную, объвленную в общем VAR разделе используют нити. Синхронизацию потоков делаю через Events (WaitForSingleObject)... Смысл "глюка" - в одной из нитей переменной присваивается значение, устанавливается SetEvent(), которого ждет основной поток. Получив Event, проверяет эту переменную и иногда эта переменная равна нулю для основного потока... т.е. никаких данных в нее не внесено. Хотя для нити эта переменная уже равна определенному значению. В общем нить присваивает переменной значение, а главная нить его некоторое время не видит. Вопрос можно решить оператором sleep(100) или пустым циклом ожидания не нуля в переменной. Но это способы неверные, т.к. sleep(100) дает совсем уж ненужную задержку, а пустой цикл неверен сам по себе, т.к. перменная может принять любое значение. Причем заметил что чаще всего это просиходит на многоядерном проце и редко на одноядерном.
Пробовал делать примерно так: Нить: [code] EnterCriticalSection aa:= aa+1; LeaveCriticalSection SetEvent(WaitForVar); [/code] Главная нить: [code] WaitForSingleObject(WaitForVar...); ... [/code]
но этот способ не помог...
Подскажите где чего можно почитать по этому поводу чтобы грамотно соорудить нужную мне конструкцию.
Да, MultiThread переменную в дельфе я ставлю в True как советует мануал, но толку от этого ноль.
-
попробуй через InterlockedIncrement()
-
-
следи за мыслью ECS
aa
LCS
SE WFS
ECS
aa aa
... ... если нужно четко мониторить все изменения "аа" - то это классическая задача на двух семафорах (RSE2)WFS1
aa
SE2 (RSE1)WFS2
aa
SE1 либо считывание тоже надо в критическую секцию обертывать(а иначе она вообще смысла не имеет) InterlockedIncrement/InterlockedExchange/etc - гарантирует атомарность изменения 32-битного значения MultiThread - "включает" критическую секцию в менеджере памяти(thread-safe Get/Free/ReallocMem, New/Dispose, создание/удалению объектов, работа со строками и динамическими массивами)...
-
> han_malign © (27.06.08 13:38) [3]
> MultiThread - "включает" критическую секцию в менеджере > памяти
IsMultiThread
-- Regards, LVT.
-
> InterlockedIncrement/InterlockedExchange/etc - гарантирует > атомарность изменения 32-битного значения
А еще гарантирует, что все процессоры увидят обновления немедленно.
-
> Причем заметил что чаще всего это просиходит на многоядерном > проце и редко на одноядерном
На одноядерном такой проблемы не должно быть. Если есть, значит ты что-то не правильно делаешь. Код в студию.
-
> LonelyWolf (27.06.08 12:01)
Без кода что-либо невозможно сказать, кроме того, что у тебя реализация неверная.
> oxffff © (28.06.08 12:46) [6] >На одноядерном такой проблемы > не должно быть.
На любом не будет проблемы.
-
> На любом не будет проблемы.
Увы это не так.
-
> Причем заметил что чаще всего это просиходит на многоядерном > проце и редко на одноядерном.
да, это верно. Любые ошибки в многопоточном приложении гораздо быстрее проявляются на многоядерных(многопроцессорных) конфигурациях, чем с одним процессором. Зато на этих конфигурациях легче отлаживаться.
-
Спасибо всем ответившим. Когда написал тут вопрос, полазил еще по сайту и нашел линк на книгу Рихтера. Там понравилось как разжевано про Mutex'ы и прочую лабуду. Увидел заодно упоминание Interlocked функций. Применил их для изменения спорной переменной. Глюк пропал. На многоядерном проце тоже. Сколько ни мучал прогу, так глюк и не выскочил. Изменил и все остальные изменения в нити глобальных переменных на IntrelockedExchange/InterlockedExchangeAdd... пока полет нормальный.
ЗЫ: > либо считывание тоже надо в критическую секцию обертывать(а > иначе она вообще смысла не имеет)
А вот об этом нигде написано не было (или я не заметил). Из доков я понял что в Critical надо оборачивать только изменение переменной, но не ее считывание. Почитав Рихтера понял что надо и там и там...
-
> Из доков я понял что в Critical надо оборачивать только > изменение переменной, но не ее считывание. Почитав Рихтера > понял что надо и там и там...
Имхо, от задачи зависит. Если переменная - ссылка на какой-нибудь глобальный TList, то работу со списком нужно обязательно заворачивать в критическую секцию. Для простых переменных, имхо, это следует делать только при необходимости.
|