Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Delphi+WinAPI (threads) - синхронизация переменных [D7, WinXP]


LonelyWolf ©   (2008-06-27 12:01:00) 

Пишу прогу-клиент 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 как советует мануал, но толку от этого ноль.


Loginov Dmitry   (2008-07-02 00:52:00) [1]

> Из доков я понял что в Critical надо оборачивать только
> изменение переменной, но не ее считывание. Почитав Рихтера
> понял что надо и там и там...


Имхо, от задачи зависит. Если переменная - ссылка на какой-нибудь глобальный TList, то работу со списком нужно обязательно заворачивать в критическую секцию. Для простых переменных, имхо, это следует делать только при необходимости.


LonelyWolf   (2008-07-01 09:23:00) [2]

Спасибо всем ответившим.
Когда написал тут вопрос, полазил еще по сайту и нашел линк на книгу Рихтера. Там понравилось как разжевано про Mutex'ы и прочую лабуду. Увидел заодно упоминание Interlocked функций.
Применил их для изменения спорной переменной. Глюк пропал. На многоядерном проце тоже. Сколько ни мучал прогу, так глюк и не выскочил.
Изменил и все остальные изменения в нити глобальных переменных на IntrelockedExchange/InterlockedExchangeAdd... пока полет нормальный.

ЗЫ:
> либо считывание тоже надо в критическую секцию обертывать(а
> иначе она вообще смысла не имеет)

А вот об этом нигде написано не было (или я не заметил). Из доков я понял что в Critical надо оборачивать только изменение переменной, но не ее считывание. Почитав Рихтера понял что надо и там и там...


Игорь Шевченко   (2008-06-28 21:43:00) [3]


> Причем заметил что чаще всего это просиходит на многоядерном
> проце и редко на одноядерном.


да, это верно. Любые ошибки в многопоточном приложении гораздо быстрее проявляются на многоядерных(многопроцессорных) конфигурациях, чем с одним процессором.
Зато на этих конфигурациях легче отлаживаться.


oxffff   (2008-06-28 21:15:00) [4]


> На любом не будет проблемы.


Увы это не так.


Тын-Дын   (2008-06-28 16:33:00) [5]


> LonelyWolf   (27.06.08 12:01) 


Без кода что-либо невозможно сказать, кроме того, что у тебя реализация неверная.


> oxffff ©   (28.06.08 12:46) [6]
>На одноядерном такой проблемы
> не должно быть.


На любом не будет проблемы.


oxffff   (2008-06-28 12:46:00) [6]


> Причем заметил что чаще всего это просиходит на многоядерном
> проце и редко на одноядерном


На одноядерном такой проблемы не должно быть.
Если есть, значит ты что-то не правильно делаешь.
Код в студию.


oxffff   (2008-06-28 12:44:00) [7]


> InterlockedIncrement/InterlockedExchange/etc - гарантирует
> атомарность изменения 32-битного значения


А еще гарантирует, что все процессоры увидят обновления немедленно.


Leonid Troyanovsky   (2008-06-27 13:45:00) [8]


> han_malign ©   (27.06.08 13:38) [3]

> MultiThread - "включает" критическую секцию в менеджере
> памяти

IsMultiThread

--
Regards, LVT.


han_malign   (2008-06-27 13:38:00) [9]

следи за мыслью
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, создание/удалению объектов, работа со строками и динамическими массивами)...


Leonid Troyanovsky   (2008-06-27 13:24:00) [10]


> LonelyWolf   (27.06.08 12:01)  

> Подскажите где чего можно почитать по этому поводу чтобы
> грамотно соорудить нужную мне конструкцию.

http://www.compress.ru/Article.aspx?id=11782

--
Regards, LVT.


clickmaker   (2008-06-27 12:15:00) [11]

попробуй через InterlockedIncrement()


Наверх

Титульная страница Поиск, карта сайта Написать письмо