Критическая секция, как совсем отключить spin count
От: Alexander G Украина  
Дата: 19.02.19 11:16
Оценка:
Пробую разные варианты задания нулевого спин каунта для крит. секции
int main()
{
    CRITICAL_SECTION cs;

    ::InitializeCriticalSection(&cs);
    printf("Spin count by default %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);

    ::InitializeCriticalSectionAndSpinCount(&cs, 0);
    printf("Spin count with zero spin count init %08X\n", cs.SpinCount );
    ::DeleteCriticalSection(&cs);


    ::InitializeCriticalSectionEx(&cs, 0, 0);
    printf("Spin count with zero spin count and flags init %08X\n", cs.SpinCount );
    ::DeleteCriticalSection(&cs);
    
    ::InitializeCriticalSection(&cs);
    ::SetCriticalSectionSpinCount(&cs, 0);
    printf("Spin count after explicit reset to zero %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);
}


Во всех вариантах значение 0x020007D0, в последнем 0x02000000.
0x7D0 это спин 2000 в десятичной.
0x02000000 это, похоже, второй из этих флагов:
#define RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO         0x01000000
#define RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN          0x02000000
#define RTL_CRITICAL_SECTION_FLAG_STATIC_INIT           0x04000000
#define RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE         0x08000000
#define RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO      0x10000000


Меня пугает этот DYNAMIC SPIN.
Как-то можно используя документируемые API его убрать?
Русский военный корабль идёт ко дну!
Re: Критическая секция, как совсем отключить spin count
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 19.02.19 11:41
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Как-то можно используя документируемые API его убрать?


Давно уже не трогал WinAPI, но что такое SpinCount? Тип у него ULONG_PTR, что больше похоже на указатель, чем на значение. Учитывая, что критические секции нельзя копировать и перемещать, кажется, что так и есть.
Re[2]: Критическая секция, как совсем отключить spin count
От: Alexander G Украина  
Дата: 19.02.19 12:00
Оценка: +1
Здравствуйте, Nuzhny, Вы писали:

N>Давно уже не трогал WinAPI, но что такое SpinCount?


Если ресурс занят, то перед тем, как ждать в ядре, может быть предпринято некоторое количество попыток проверить, не освободился ли ресурс.
На многопроцессорных/многоядерных системах и для занимаемых на непродолжительное время ресурсов это может улучшить перформанс.
Для продолжительно занимаемых ресурсов от такого больше вреда, чем пользы.
На однопроцессорных/одноядерных системах это бесполезно, и оно не включается.

В книге Рихтера тема раскрыта и в одкументации той же InitializeCriticalSectionAndSpinCount.

N>Тип у него ULONG_PTR, что больше похоже на указатель, чем на значение.


Оно там для выравнивания с /Zp1, даже комментарий есть:

typedef struct _RTL_CRITICAL_SECTION {
    ...
    ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;


Значение явно в младшей части спин каунт.
Русский военный корабль идёт ко дну!
Отредактировано 19.02.2019 14:29 Alexander G . Предыдущая версия . Еще …
Отредактировано 19.02.2019 12:22 Alexander G . Предыдущая версия .
Отредактировано 19.02.2019 12:02 Alexander G . Предыдущая версия .
Отредактировано 19.02.2019 12:01 Alexander G . Предыдущая версия .
Re: Критическая секция, как совсем отключить spin count
От: Mr.Delphist  
Дата: 19.02.19 12:08
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Пробую разные варианты задания нулевого спин каунта для крит. секции


А что возвращается в качестве результата? Если вызовы по факту неуспешны, то что говорит GetLastError?
Re[2]: Критическая секция, как совсем отключить spin count
От: Alexander G Украина  
Дата: 19.02.19 12:19
Оценка:
Здравствуйте, Mr.Delphist, Вы писали:

MD>Здравствуйте, Alexander G, Вы писали:


AG>>Пробую разные варианты задания нулевого спин каунта для крит. секции


MD>А что возвращается в качестве результата? Если вызовы по факту неуспешны, то что говорит GetLastError?


Все вызовы успешны, значение GetLastError не меняется.

В принципе эти функции никогда не фейлят, обычная InitializeCriticalSection даже не возвращает значение
(В старых версиях Windows она могла бросать SEH-исключения, сейчас она просто всегда успешна).

Функция SetCriticalSectionSpinCount в примере возвращает 0x7D0, что также подтверждает, что дефолтный спин каунт 0x7D0, а 0x02000000 — это флаг.
Русский военный корабль идёт ко дну!
Re[3]: Критическая секция, как совсем отключить spin count
От: Mr.Delphist  
Дата: 19.02.19 12:50
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, Mr.Delphist, Вы писали:


MD>>Здравствуйте, Alexander G, Вы писали:


AG>>>Пробую разные варианты задания нулевого спин каунта для крит. секции


MD>>А что возвращается в качестве результата? Если вызовы по факту неуспешны, то что говорит GetLastError?


AG>Все вызовы успешны, значение GetLastError не меняется.


AG>В принципе эти функции никогда не фейлят, обычная InitializeCriticalSection даже не возвращает значение

AG>(В старых версиях Windows она могла бросать SEH-исключения, сейчас она просто всегда успешна).

AG>Функция SetCriticalSectionSpinCount в примере возвращает 0x7D0, что также подтверждает, что дефолтный спин каунт 0x7D0, а 0x02000000 — это флаг.


Кстати, я тут нагуглил разбор потрохов этого API — возможно, будет интересно:

Multithreading — everything they want you to know. Part 1 — Critical Sections
https://forum.reverse4you.org/showthread.php?t=2607&s=01c4f07aed777d970cd9dc8b3790bbce


Невзирая на англоязычный заголовок, сам разбор на русском языке.
Re: Решение существует
От: Alexander G Украина  
Дата: 23.02.19 10:38
Оценка:
Нужно передать ненулевой спин каунт в InitializeCriticalSectionAndSpinCount или InitializeCriticalSectionEx, тогда дополнительных флагов не будет:

    ::InitializeCriticalSectionEx(&cs, 1, 0);
    printf("Spin count after explicit one %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);


Это выведет 1, спин каунт 1 — это почти что ноль. Последующим вызовом SetCriticalSectionSpinCount можно и строго ноль получить:

    ::InitializeCriticalSectionEx(&cs, 1, 0);
    ::SetCriticalSectionSpinCount(&cs, 0);
    printf("Spin count after explicit one and then reset to zero %08X\n", cs.SpinCount);
    ::DeleteCriticalSection(&cs);
Русский военный корабль идёт ко дну!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.