На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Sleep - что внутри?
    Бесконечный цикл со Sleep(1) почти не грузит процессор.
    Что там такого зашито внутри? Как это можно реализовать кроме как через Sleep?
      Цитата Jin X @
      Бесконечный цикл со Sleep(1) почти не грузит процессор.
      Довольно логично: задача Sleep'а - указать ОС, что "такой-то процесс не работает, можете заняться своими делами", что она и делает.
      Цитата Jin X @
      Как это можно реализовать кроме как через Sleep?
      Уточните, что подразумевается под словом 'это'? Если "загрузку ЦП", то можно банально в цикле считать x=cos(x) и загрузка будет выше крыши (но одно ядро, конечно). (Тривиальное распараллеливание загрузит все ядра).
        Цитата Jin X @
        Бесконечный цикл со Sleep(1) почти не грузит процессор.
        Что там такого зашито внутри?

        Во-первых, зашито само название функции - Sleep, т.е. поток "засыпает" (приостанавливается) на время >= указанного значения. Во-вторых, "зашита" специфика отсчета времени в ОС - счет ведется дискретно по прерываниям системного таймера со стандартным (дефолтным) интервалом в 1/64 сек = 15.625 мс. Отсюда и существенная разница Sleep со значением 0 и > 0. В любом случае вызов Sleep передает управление ОС, которая должна запустить следующий по очереди "простаивающий и готовый к исполнению" поток на данном процессоре. Но если система не загружена и таковых потоков нет, то при Sleep(0) управление практически сразу возвращается вызвавшему эту функцию потоку. А в случае Sleep(X > 0) ОС обязана выдержать интервал времени не менее заданного, но поскольку счет времени ведется дискретно, то возобновление исполнения потока происходит только по очередному тику сис.таймера, т.е. с задержкой от 0 до 15.625 мс при первом или однократном вызове Sleep и с задержкой, близкой к 15 мс при вызове Sleep в "пустом\холостом" цикле (за счет авто-синхронизации с сис. таймером). В итоге получается, что при вызове в холостом цикле Sleep(1) практически эквивалентна Sleep(15). Вот и прикинь загрузку процессора - несколько "жалких" сотен (или даже тысяч - роли не играет) тактов на вызов Sleep с переходом в ядро и ~15 мс*(частота_процессора) тактов чистого сна. Ес-но, что "Бесконечный цикл со Sleep(1) почти не грузит процессор"
          Цитата Jin X @
          Что там такого зашито внутри?

          ExpandedWrap disabled
            event = CreateEvent(NULL, FALSE, FALSE, NULL);
            //...
            void Sleep(DWORD timeot)
            {
               WaitForSingleObject(event, timeout);
            }


          Добавлено
          На самом деле функция делает ничто иное как переводит поток в очередь спящих потоков с таймаутом пробуждения и переключает поток. Не грузит она потому что во время таймаута работают другие потоки.

          Добавлено
          Цитата leo @
          В итоге получается, что при вызове в холостом цикле Sleep(1) практически эквивалентна Sleep(15).

          Я конечно не знаю как там в виндах реализовано, но я делал пробуждалку не только по таймеру.

          Добавлено
          Цитата Jin X @
          Как это можно реализовать кроме как через Sleep?

          А зачем оно надо?
          Сообщение отредактировано: shm -
            Цитата Славян @
            Уточните, что подразумевается под словом 'это'?
            Наоборот разгрузку. Мне нужно сделать цикл (spin-lock, в частности), который будут грузить проц минимально.
            Полагаю, что Sleep(1) - это не самый оптимальный способ сделать это.
              Вот ещё такой вариант нашёлся:
              Цитата \win2k\private\windows\media\avi\drawdib.16\ddt\ddt.c
              ExpandedWrap disabled
                void Sleep(UINT uSleep)
                {
                    MSG msg;
                    int id;
                 
                    id = SetTimer(NULL, 42, uSleep, NULL);
                 
                    while (GetMessage(&msg, NULL, 0, 0))
                    {
                        if (msg.message == WM_TIMER && msg.wParam == (WORD)id)
                            break;
                 
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                 
                    KillTimer(NULL, id);
                }
              Он выглядит несколько лучше, ибо всё приложение не "виснет" во время такой спячки, а хоть как-то реагирует.
                Ок. Чем же можно разгрузить проц на очень короткий срок (мкс, грубо говоря), кроме Sleep'а?

                Добавлено
                К сожалению, pause не разгружает проц вообще никак :(
                  Цитата Jin X @
                  К сожалению, pause не разгружает проц вообще никак

                  Разгружает, но не передает управление остальным потокам, так что как минимум стоит вставить еще и SwitchToThread. Загрузка проца в Винде имеет лишь посредственное отношение к фактической загрузке, а конкретно она высчитывается из фактического времени работы потока. Т. е. если в системе все потоки кроме твоего спят, а твой занят хоть чем-то кроме сна, то загрузка и будет 100%. Мне кажется в твоем случае стоит задуматься над событийной (асинхронной) моделью программы. Т. е. вместо твоего пустого цикла использовать WaitForSingleObject для ожидания результата чего-то. Тогда проблемы с пустой нагрузкой отпадут сами собой.

                  Добавлено
                  И да, если поток gui'шный, то можно использовать обработку сообщений потока через PostThreadMessage.
                  Сообщение отредактировано: shm -
                    Цитата shm @
                    Разгружает, но не передает управление остальным потокам, так что как минимум стоит вставить еще и SwitchToThread. Загрузка проца в Винде имеет лишь посредственное отношение к фактической загрузке, а конкретно она высчитывается из фактического времени работы потока. Т. е. если в системе все потоки кроме твоего спят, а твой занят хоть чем-то кроме сна, то загрузка и будет 100%. Мне кажется в твоем случае стоит задуматься над событийной (асинхронной) моделью программы. Т. е. вместо твоего пустого цикла использовать WaitForSingleObject для ожидания результата чего-то. Тогда проблемы с пустой нагрузкой отпадут сами собой.
                    А как я могу ждать обнуления 32-битной переменной через WaitForSingleObject?

                    Я запускал несколько потоков @: pause jmp @ и смотрел на температуру процессоров. Так вот, наличие pause никак не неё не влияет. Так что, у меня с разгрузкой всё-таки вопрос...

                    На данный момент решил сделать spin-loop-циклы вот так:

                    ( ( 265 spin-циклов, затем SwitchToThread ) * 4 раза, затем Sleep(1) ) * 4 раза.
                    Итого выходит 4096 циклов. Не так много, но и не мало.
                    После этого переходим на Sleep(1) после каждой проверки, максимально разгружая таким образом проц.

                    Готов обсудить цифры 256, 4, 4 на предмет оптимальности :)
                      Цитата shm @
                      Загрузка проца в Винде имеет лишь посредственное отношение к фактической загрузке
                      В продолжение темы: каким образом ядро делает так, что температура процессора остаётся низкой? А любой поток, делая даже pause в цикле будет нагревать его? На ум приходит только hlt, но...?
                        Цитата Jin X @
                        А как я могу ждать обнуления 32-битной переменной через WaitForSingleObject?

                        Явно никак. Но ты можешь в том месте, где ее устаналиаешь, добавить еще SetEvent. И все будет ОК.

                        Добавлено
                        Цитата Jin X @
                        Так вот, наличие pause никак не неё не влияет.

                        Довольно странно. Видимо в твоем процессоре такая реализация.
                        Цитата Jin X @
                        ( ( 265 spin-циклов, затем SwitchToThread ) * 4 раза, затем Sleep(1) ) * 4 раза.
                        Итого выходит 4096 циклов. Не так много, но и не мало.
                        После этого переходим на Sleep(1) после каждой проверки, максимально разгружая таким образом проц.

                        Криво и косо.
                        Цитата Jin X @
                        В продолжение темы: каким образом ядро делает так, что температура процессора остаётся низкой?

                        В системе есть System Idle потоки на каждое ядро. Они выполняют либо hlt, либо специальный aml код из acpi (и то и другое недоступно для user mode).
                          Цитата shm @
                          Довольно странно. Видимо в твоем процессоре такая реализация.
                          Я проверил это на 2-х процессорах: у меня на i5 (декстоп), на другом i5 (ноутбук) (позже ещё на i3 проверю, на другом ноуте). Результат один. Я даже больше скажу: с pause чуть больше греет :)

                          Цитата shm @
                          Криво и косо.
                          В чём кривизна? Как тогда не криво и не косо сделать?
                          Сделать через ивенты? (Но по любому же первые N (например, 4096) циклов надо будет оставить) :whistle:
                            Цитата Jin X @
                            Я даже больше скажу: с pause чуть больше греет

                            Будет время - я у себя протестирую.
                            Цитата Jin X @
                            В чём кривизна?

                            В том, что ты вместо использования готовых средств синхронизации занимаешься их эмуляцией.
                            Цитата Jin X @
                            (Но по любому же первые N (например, 4096) циклов надо будет оставить)

                            ExpandedWrap disabled
                              if N < 4094 then
                              ...
                              else
                                 WaitFor...
                              Цитата shm @
                              В том, что ты вместо использования готовых средств синхронизации занимаешься их эмуляцией.
                              Изначально была идея просто сделать spin-lock, но с экономией ресурсов, если процесс затянется. С использованием 1 простой переменной типа DWord или Int64, без Initialize и Delete. Т.е. наиболее быстрый и с наименьшими заморочками.

                              Сдаётся мне, что установка/ожидание event'а процесс тяжёлый... Хотя, могу ошибаться.
                                Я что скажу: если у тебя spin-локи грузят проц, то значит нужны эвенты или иные средства синхронизации (ибо цикл синхронизации отнюдь не маленький), которые могут усыпить поток. Во всяком случае что это процесс не тяжелее, чем sleep.
                                Сообщение отредактировано: shm -
                                  Synchronization Functions

                                  Critical section
                                  Slim Reader/Writer (SRW)

                                  и возможно
                                  One-time initialization
                                  Synchronization barrier
                                    Цитата Jin X @
                                    Сдаётся мне, что установка/ожидание event'а процесс тяжёлый... Хотя, могу ошибаться.
                                    Цитата shm @
                                    Во всяком случае что это процесс не тяжелее, чем sleep.
                                    Реально...
                                    Замерил скорость выполнения разного кода (в тактах), получилось вот что:
                                    ExpandedWrap disabled
                                      Холостой ход - 30-60
                                      cmpxchg (10 раз) - 60-120
                                      lock cmpxchg (10 раз) - 400-550
                                      SpinLoop 1024 циклов (cmp) - 26000-36000
                                      SpinLoop 1024 циклов (locked cmpxchg) - 50000-70000
                                       
                                      CreateEvent - 30000-50000
                                      Set/ResetEvent - 2000-4000
                                      CloseHandle - 4000-7000
                                      SwitchToThread - 2500-4000
                                      Sleep(0) - 3000-5000
                                      Sleep(1) - 160 тыс-3 млн
                                      WaitForSingleObject (signaled) - 2000-5000
                                      InitializeCriticalSectionAndSpinCount - 1800-2800
                                      InitializeCriticalSection - 1400-2400
                                      EnterCriticalSection (свободная) - 80-150
                                      EnterCriticalSection (рекурсивно) - 100-300
                                      DeleteCriticalSection - 500-1500
                                    CreateEvent хоть и долгая тема, но CreateEvent+Set/ResetEvent+WaitForSingleObject по любому шустрее...

                                    Добавлено
                                    Shaggy, гляну, thanx!
                                      Вопрос: есть ли гарантия, что WaitForSingleObject успеет сработать, если другой поток сделает SetEvent и CloseHandle подряд?
                                        Цитата Jin X @
                                        CreateEvent хоть и долгая тема

                                        Его нужно дернуть 1 раз при запуске и все.
                                        Цитата Jin X @
                                        есть ли гарантия, что WaitForSingleObject успеет сработать, если другой поток сделает SetEvent и CloseHandle подряд?

                                        А зачем так делать? Нет, нету гарантий. Если уж так надо, то после WaitForSingleObject и закрывай.
                                          Цитата shm @
                                          Его нужно дернуть 1 раз при запуске и все.
                                          Если сделать инициализацию 1 раз, значит нужно делать и удаление (типа DeleteCriticalSection), а я хочу сделать только Lock (Enter) и Unlock (Leave). Есть прикольные функции: WaitOnAddress и WakeByAddressSingle/WakeByAddressAll, жаль только, что существуют они в Windows 8+ (посему придётся комбинировать их и Event'ы для поддержки работы в Windows 7/XP).
                                            Jin X
                                            А свою написать?

                                            Мне не понравилось то что для критической секции нужна глобальная переменная. И я сделал вой вариант.

                                            ExpandedWrap disabled
                                              procedure TaskSwitch;
                                              var
                                                Cis:PCriticalSection;
                                                Status:Boolean;
                                              begin
                                                Status:=GetIntStatus;
                                                DisableInt;
                                                CisBegin(Cis);
                                                  if TaskSetModeCmd.Lock=MUnLocked then
                                                     ExecuteCMD;
                                                  AlgTaskSwitch;
                                                CisEnd(Cis);  
                                                if Status=False then
                                                   EnableInt;
                                              end;

                                            Прикреплённый файлПрикреплённый файлUSynchronization.pas (9,15 Кбайт, скачиваний: 316)

                                            Добавлено
                                            PS. Код сырой и не тестированный. Просто как пример.
                                            Сообщение отредактировано: Pavia -
                                              Цитата Jin X @
                                              Если сделать инициализацию 1 раз, значит нужно делать и удаление (типа DeleteCriticalSection), а я хочу сделать только Lock (Enter) и Unlock (Leave)

                                              Это неэффективно. Неужели так лень пару лишних функций вызвать?
                                              Pavia, :wacko:
                                              Я не претендую на правильность, но все же.
                                              ExpandedWrap disabled
                                                class CriticalSection: private Event
                                                {
                                                    static void EnterSingle(CriticalSection *cs)
                                                    {
                                                        //std::cout << "EnterSingle" << std::endl;
                                                    }
                                                    static void LeaveSingle(CriticalSection *cs)
                                                    {
                                                        //std::cout << "LeaveSingle" << std::endl;
                                                    }
                                                    static void EnterMultitasking(CriticalSection *cs);
                                                    static void LeaveMultitasking(CriticalSection *cs);
                                                    static void EnterSmp(CriticalSection *cs);
                                                    static void LeaveSmp(CriticalSection *cs);
                                                    static void (*EnterProc)(CriticalSection *cs);
                                                    static void (*LeaveProc)(CriticalSection *cs);
                                                    volatile atom State;
                                                //  atom LockCounter;
                                                    //locked
                                                    bool OnWaitBegin();
                                                    //bool OnSetStateSingle(Thread *);
                                                public:
                                                    class Lock
                                                    {
                                                        CriticalSection *section;
                                                    public:
                                                        Lock(CriticalSection &cs)
                                                        {
                                                            section = &cs;
                                                            cs.enter();
                                                        }
                                                        ~Lock()
                                                        {
                                                            section->leave();
                                                        }
                                                    };
                                                    CriticalSection();
                                                    CriticalSection(bool Busy);
                                                    static void SetMutlitaskingMode()
                                                    {
                                                        EnterProc = &EnterMultitasking;
                                                        LeaveProc = &LeaveMultitasking;
                                                    }
                                                    static void SetSmpMode()
                                                    {
                                                        EnterProc = &EnterSmp;
                                                        LeaveProc = &LeaveSmp;
                                                    }
                                                    void enter()
                                                    {
                                                        EnterProc(this);
                                                    }
                                                    void leave()
                                                    {
                                                        LeaveProc(this);
                                                    }
                                                    bool IsLock() const
                                                    {
                                                        return (State != 0);
                                                    }
                                                    bool enter(DWORD Timeout);
                                                };
                                                //...
                                                void CriticalSection::EnterSmp(CriticalSection *cs)
                                                {
                                                    static const int max_spin_it = 1024;
                                                    unsigned int cpu_id, result;
                                                    int i;
                                                    cpu_id = GetCurrentCpuId() + 1;
                                                    result = CpuCompareAndSwapLock<volatile atom>(&cs->State, 0, cpu_id);
                                                    if(result == 0)
                                                        return;
                                                    else if(result != cpu_id)
                                                    {
                                                        for(i = 0; i < max_spin_it; i++)
                                                        {
                                                            if(cs->State == 0)
                                                            {
                                                                cpu_id = GetCurrentCpuId() + 1;
                                                                result = CpuCompareAndSwapLock<volatile atom>(&cs->State, 0, cpu_id);
                                                                if(result == 0)
                                                                    return;
                                                            }
                                                            CpuPause();
                                                        }
                                                    }
                                                    cs->Wait();
                                                    cs->State = GetCurrentCpuId() + 1;
                                                }
                                                 
                                                void CriticalSection::LeaveSmp(CriticalSection *cs)
                                                {
                                                    if(cs->HaveWaitingThreads())
                                                        cs->SetState();
                                                    else
                                                        cs->State = 0;
                                                }
                                                Pavia, what's that?
                                                ExpandedWrap disabled
                                                  uses SysSupport, UMemoryManager, UMemoryMap;
                                                :)
                                                Добавлено
                                                Цитата Pavia @
                                                А свою написать?
                                                Что именно написать своё?



                                                shm, то ли неполный код, то ли... х/з.
                                                GetCurrentCpuId - ?
                                                CpuCompareAndSwapLock - ?
                                                Wait - ?
                                                SetState - ?
                                                HaveWaitingThreads - ?
                                                ...
                                                  shm
                                                  Цитата shm @
                                                  Pavia, :wacko:

                                                  Я хотел показать метод с патчингом.
                                                  В стеке страниц выделяем страницы. Страницы связаны в цепочку двойным списком.
                                                  В этих страницах хранятся адреса критических секций и её данные как то мьютекс.
                                                  При 1 заходе в критическую секцию адрес патчится на спинлок.

                                                  Для задачи Jin X:
                                                  Цитата Jin X @
                                                  Если сделать инициализацию 1 раз, значит нужно делать и удаление (типа DeleteCriticalSection), а я хочу сделать только Lock (Enter) и Unlock (Leave).

                                                  Можно сделать по аналогии патч который накладывает 5-байтовый NOP.
                                                  Сообщение отредактировано: Pavia -
                                                    Цитата Jin X @
                                                    shm, то ли неполный код, то ли... х/з.

                                                    Это для Pavia. Код не имеет никакого отношения к Win, как и код Pavia. Да простят нас админы за оффтоп.

                                                    Добавлено
                                                    Pavia, я у тебя не вижу усыпления потока. Без этого твои мьютексы это скорее спинлок, что крайне неэффективно в силу очевидных причин. Связанный список я у себя храню прямо в структуре потока, которую очень легко достать средствами TLS.
                                                    Сообщение отредактировано: shm -
                                                      Цитата Jin X @
                                                      Замерил скорость выполнения разного кода (в тактах), получилось вот что:
                                                      lock cmpxchg (10 раз) - 400-550
                                                      pinLoop 1024 циклов (locked cmpxchg) - 50000-70000

                                                      Это для случая, когда только один поток крутит спин-луп. Если же его будут крутить два и более потока одновременно, то эти цифирьки могут увеличиться в несколько раз (где-то от 3 до 5). Дело в том, что lock cmpxchg в любом случае производит запись в переменную (записывается либо новое, либо старое значение), поэтому соответствующая линейка кэша оказывается модифицированной, со всеми вытекающими последствиями синхронизации кэшей 1-2 уровня при многопоточном доступе. В случае одного потока модифицированная линейка остается в кэше L1 того ядра, на котором работает поток. А в случае двух и более потоков, она постоянно перебрасывается из L1 одного ядра в L1 другого через общий L3. Поэтому, чтобы избежать этих перебросов, в приведенных тобой примерах от Intel перед lock-обменом используется простое сравнение переменной "только на чтение". В этом случае, при наличии нескольких ожидающих потоков, они до снятия лока только читают линейку, не изменяя ее, и соотв-но она находится в неизменном shared состоянии в L1 этих потоков\ядер
                                                        Цитата leo @
                                                        Дело в том, что lock cmpxchg в любом случае производит запись в переменную (записывается либо новое, либо старое значение)
                                                        Я даже скажу, что lock вообще сильно тормозит процесс. Особенно если это будут делать одновременно несколько потоков...

                                                        Из Intel Instruction Set Reference (cmpxchg):
                                                        ExpandedWrap disabled
                                                          TEMP ← DEST
                                                          IF accumulator = TEMP
                                                            THEN
                                                              ZF ← 1;
                                                              DEST ← SRC;
                                                            ELSE
                                                              ZF ← 0;
                                                              accumulator ← TEMP;
                                                              DEST ← TEMP;
                                                          FI;
                                                        А вообще, непонятно, зачем cmpxchg делает запись во втором случае. Можно было бы обойтись и без неё.
                                                          Цитата Jin X @
                                                          Можно было бы обойтись и без неё.

                                                          Как?
                                                            Цитата shm @
                                                            Как?
                                                            А в чём её суть?

                                                            Temp := Dest
                                                            Dest := Temp
                                                              Быть может там прописана технология реализации. Т.е. TEMP - a'la кэш, а в конце команды обязательно надо что-то послать в память, ну а потому как совпадёт кэш с DEST, то не страшно его и послать обратно!?? :unsure:
                                                                Цитата Jin X @
                                                                А в чём её суть?

                                                                В атомарности.
                                                                Цитата Jin X @
                                                                Temp := Dest
                                                                Dest := Temp

                                                                Ни разу не атомарно.
                                                                  Цитата Jin X @
                                                                  А вообще, непонятно, зачем cmpxchg делает запись во втором случае. Можно было бы обойтись и без неё.

                                                                  Это делается для упрощения "железной логики":
                                                                  Цитата Intel
                                                                  To simplify the interface to the processor’s bus, the destination operand receives a write cycle without regard to the result of the comparison. ... (The processor never produces a locked read without also producing a locked write.)
                                                                  А избежать лишних тормозов при вызове cmpxchg в спин-цикле можно программно, добавив перед lock обычное сравнение (как рекомендует интел - “test, test-and-set” technique).
                                                                    Цитата shm @
                                                                    В атомарности.
                                                                    Цитата shm @
                                                                    Ни разу не атомарно.
                                                                    Иии?
                                                                    Я не понимаю, что ты хочешь сказать :)
                                                                    Приведённый мной выше код - это внутренняя логика инструкции cmpxchg.

                                                                    leo, теперь ясно.
                                                                      Цитата Jin X @
                                                                      Я не понимаю, что ты хочешь сказать

                                                                      То, что именно такая форма инструкции удобна для реализации lock-free алгоритмов и те же примитивов синхронизации.
                                                                        shm, ничуть не удобна. Потому что пока она будет делать Temp = Dest и Dest = Accumulator (в случае успешной проверки входа критической секции), то же самое может сделать и другой. И оба войдут в неё.

                                                                        Temp1 = Dest
                                                                        Temp2 = Dest
                                                                        Temp1 = Src ? (Yes)
                                                                        Temp2 = Src ? (Yes)
                                                                        Dest = Accumulator
                                                                        Dest = Accumulator

                                                                        Добавлено
                                                                        Или мы о разном? :)
                                                                          Цитата Jin X @
                                                                          Потому что пока она будет делать

                                                                          Она это делает атомарно (при наличии lock префикса и для SMP). Ну как еще написать не знаю.

                                                                          Добавлено
                                                                          Аппаратно эта инструкция, насколько я понимаю, реализована совсем не так, как ты расписал.

                                                                          Добавлено
                                                                          Я с трудом представляю как без этой инструкции можно реализовать тот же lock-free список. Если у тебя есть идеи - покажи. Кстати эта функция именно в таком виде используется в реализации практически всех примитивов синхронизации.
                                                                          Сообщение отредактировано: shm -
                                                                            Цитата shm @
                                                                            Она это делает атомарно (при наличии lock префикса и для SMP). Ну как еще написать не знаю.
                                                                            При наличии lock - естественно. Но ты ж сам написал:
                                                                            Цитата shm @
                                                                            То, что именно такая форма инструкции удобна для реализации lock-free алгоритмов и те же примитивов синхронизации.
                                                                            Если же имелось в виду:
                                                                            Цитата
                                                                            Неблокирующая синхронизация — подход в параллельном программировании на симметрично-многопроцессорных системах, проповедующий отказ от традиционных примитивов блокировки, таких, как семафоры, мьютексы и события. Разделение доступа между потоками идёт за счёт атомарных операций и специальных, разработанных под конкретную задачу, механизмов блокировки.
                                                                            © Википедия
                                                                            тогда без вопросов ;)

                                                                            Цитата shm @
                                                                            Аппаратно эта инструкция, насколько я понимаю, реализована совсем не так, как ты расписал.
                                                                            Это код из свежего Intel Instruction Reference (сообщение #27).

                                                                            Добавлено
                                                                            Цитата shm @
                                                                            Кстати эта функция именно в таком виде используется в реализации практически всех примитивов синхронизации.
                                                                            Так, а кто ж спорит-то? :)
                                                                              Цитата Jin X @
                                                                              тогда без вопросов

                                                                              именно.
                                                                              Цитата Jin X @
                                                                              Это код из свежего Intel Instruction Reference

                                                                              Это псевдо-код поясняющий поведение инструкции. Он не имеет никакого отношения к ее аппаратной реализации.

                                                                              Добавлено
                                                                              Цитата Jin X @
                                                                              Так, а кто ж спорит-то?

                                                                              А тогда ивзини, я неправильно понял твою реплику про cmpxchg. Тогда leo правильно написал.
                                                                              Сообщение отредактировано: shm -
                                                                                Нашёл интересную вещь в недрах AcquireSRWLockExclusive: NtWaitForKeyedEvent (ntdll.dll).
                                                                                Возможно, это то, что мне нужно (если вернуться к первоначальной теме)...
                                                                                Буду изучать... http://www.locklessinc.com/articles/keyed_events/ :whistle:
                                                                                  Jin X, так обычные события чем не угодили я все понять не могу?
                                                                                    Уффф... Надо делать Init и Detele (в которых делается Init и Close... ну или просто Delete (Close) (либо создавать и удалять на каждом входе/выходе в/из крит.секции). Они более громоздкие/долгие. Надо делать отдельное событие под каждую критическую секцию (под каждый мьютекс). Короче, этот вариант мне кажется более интересным. Правда, это не совсем то, что я подумал изначально. Изначально мне казалось, что это альтернатива Sleep(1). Но всё равно лучше, чем Event. Вероятно. Я ещё не изучил этот вопрос :)
                                                                                      Цитата Jin X @
                                                                                      Надо делать Init и Detele

                                                                                      Ой да целых пара наносекунд при запуске и завершении твоей программы, ога.
                                                                                      Цитата Jin X @
                                                                                      либо создавать и удалять на каждом входе/выходе в/из крит.секции

                                                                                      Не надо ничего создавать и удалять во время работы. Надо:
                                                                                      Enter
                                                                                      ...
                                                                                      Leve
                                                                                      инициализацию и удаления нужно вынести из основного цикла.
                                                                                      Цитата Jin X @
                                                                                      Надо делать отдельное событие под каждую критическую секцию

                                                                                      :wacko:
                                                                                      Цитата Jin X @
                                                                                      Но всё равно лучше, чем Event

                                                                                      Что лучше?
                                                                                      Сообщение отредактировано: shm -
                                                                                        Цитата Jin X @
                                                                                        Нашёл интересную вещь в недрах AcquireSRWLockExclusive: NtWaitForKeyedEvent (ntdll.dll).
                                                                                        Возможно, это то, что мне нужно (если вернуться к первоначальной теме)...

                                                                                        Во-первых, NtWaitForKeyedEvent работает через тот же event, с той разницей, что 1) к одному эвенту можно прицепить несколько ключей (что несколько замедляет быстродействие, о котором ты так печешься), 2) если вместо первого параметра передать nil\null, то будет использован системный эвент (типа CritSecOutOfMemoryEvent) - возможно это "то, что тебе нужно", если тебе так хочется избежать "лишних" Create\Close, Init\Delete и т.п.
                                                                                        Во-вторых, механизм использования NtWaitForKeyedEvent давно встроен в виндовые крит.секции (по кр.мере со времен XP) на случай облома создания собственного эвента крит.секции (по причине OutOfMemory или исчерпания лимита хэндлов). Поэтому, если тебе так нравится изобретать нестандартные велосипеды, то можно использовать небольшой хак с обычной крит.секцией - сразу после InitializeCriticalSectionAndSpinCount(cs,...), установить cs.LockSemaphore:=INVALID_HANDLE_VALUE - и всё, получишь два в одном: и готовый спин-луп с заданным числом повторений и ожидание NtWaitForKeyedEvent на системном эвенте (вместо создания собственного эвента для крит.секции и его ожидания на WaitForSingleObject).
                                                                                          leo, интересно... :)
                                                                                          Почему же AcquireSRWLockShared, AcquireSRWLockExclusive не используют обычные Event'ы, а работают с KeyedEvent'ами?
                                                                                            Цитата Jin X @
                                                                                            Почему же AcquireSRWLockShared, AcquireSRWLockExclusive не используют обычные Event'ы, а работают с KeyedEvent'ами?

                                                                                            Потому, что это slim - упрощенный "до безобразия" вариант крит.секции. Структура SRWLOCK это набор битовых полей, упакованных в размер указателя (32 или 64 бита). В ней просто нет места не только для указателя на event, но и для OwningThreadID и RecursionCount (со всеми вытекающими особенностями использования по сравнению с крит.секцией). Индивидуального SpinCount-а тоже нет, используется некое дефолтное значение. Соотв-но и для ожидания освобождения лока используется не "обычный", а некий глобальный системный KeyedEvent.

                                                                                            PS: Что касается быстродействия поиска ключа, то оно зависит от кол-ва, этих самых ключей, привязанных к одному KeyedEvent-у, ну и от используемой структуры хранения и алгоритма поиска ключей. В XP KeyedEvent использовался только в критической ситуации нехватки памяти, поэтому о быстродействии особо не беспокоились и использовали для хранения ключей простой список. А начиная с висты KeyedEvent-ы стали использовать для SRW-lock, условных переменных и т.п., и соотв-но стали хранить ключи в хэш-таблице для ускорения их поиска. Однако как бы не было реализовано хранение и поиск ключей, при малом\небольшом их кол-ве накладные расходы на их поиск\добавление\удаление составляют незначительный процент от общего времени ожидания эвента на NtWaitForKeyedEvent -> WaitForSingleObject
                                                                                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                                                                            0 пользователей:


                                                                                            Рейтинг@Mail.ru
                                                                                            [ Script execution time: 0,1043 ]   [ 18 queries used ]   [ Generated: 29.03.24, 08:31 GMT ]