Конференция "Основная" » Delphi+WinAPI (threads) - синхронизация переменных [D7, WinXP]
 
  • LonelyWolf (27.06.08 12:01) [0]
    Пишу прогу-клиент 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 как советует мануал, но толку от этого ноль.
  • clickmaker © (27.06.08 12:15) [1]
    попробуй через InterlockedIncrement()
  • Leonid Troyanovsky © (27.06.08 13:24) [2]

    > LonelyWolf   (27.06.08 12:01)  

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

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

    --
    Regards, LVT.
  • han_malign © (27.06.08 13:38) [3]
    следи за мыслью
    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 © (27.06.08 13:45) [4]

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

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

    IsMultiThread

    --
    Regards, LVT.
  • oxffff © (28.06.08 12:44) [5]

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


    А еще гарантирует, что все процессоры увидят обновления немедленно.
  • oxffff © (28.06.08 12:46) [6]

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


    На одноядерном такой проблемы не должно быть.
    Если есть, значит ты что-то не правильно делаешь.
    Код в студию.
  • Тын-Дын © (28.06.08 16:33) [7]

    > LonelyWolf   (27.06.08 12:01) 


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


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


    На любом не будет проблемы.
  • oxffff © (28.06.08 21:15) [8]

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


    Увы это не так.
  • Игорь Шевченко © (28.06.08 21:43) [9]

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


    да, это верно. Любые ошибки в многопоточном приложении гораздо быстрее проявляются на многоядерных(многопроцессорных) конфигурациях, чем с одним процессором.
    Зато на этих конфигурациях легче отлаживаться.
  • LonelyWolf (01.07.08 09:23) [10]
    Спасибо всем ответившим.
    Когда написал тут вопрос, полазил еще по сайту и нашел линк на книгу Рихтера. Там понравилось как разжевано про Mutex'ы и прочую лабуду. Увидел заодно упоминание Interlocked функций.
    Применил их для изменения спорной переменной. Глюк пропал. На многоядерном проце тоже. Сколько ни мучал прогу, так глюк и не выскочил.
    Изменил и все остальные изменения в нити глобальных переменных на IntrelockedExchange/InterlockedExchangeAdd... пока полет нормальный.

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

    А вот об этом нигде написано не было (или я не заметил). Из доков я понял что в Critical надо оборачивать только изменение переменной, но не ее считывание. Почитав Рихтера понял что надо и там и там...
  • Loginov Dmitry © (02.07.08 00:52) [11]
    > Из доков я понял что в Critical надо оборачивать только
    > изменение переменной, но не ее считывание. Почитав Рихтера
    > понял что надо и там и там...


    Имхо, от задачи зависит. Если переменная - ссылка на какой-нибудь глобальный TList, то работу со списком нужно обязательно заворачивать в критическую секцию. Для простых переменных, имхо, это следует делать только при необходимости.
 
Конференция "Основная" » Delphi+WinAPI (threads) - синхронизация переменных [D7, WinXP]
Есть новые Нет новых   [134491   +13][b:0][p:0.001]