InterlockedIncrement vs. Mutex
От: RS Земля ICQ: 148844272
Дата: 27.02.02 12:57
Оценка:
Делаю на API COM-сервер, к которому возможно обращение из нескольких потоков одного процесса. По идее, внутренний счетчик, модифицируемый методами AddRef и Release, должен быть доступен только одному потоку. Можно использовать mutex, но узнал об интересных функциях InterlockedIncrement и InterlockedDecrement. В описании этих функций указано, что на многопроцессорных машинах адрес счетчика должен быть выровнен на границу 32 бита. А теперь, внимание, вопрос: что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита или использовать mutex?
Re: InterlockedIncrement vs. Mutex
От: TepMuHyc  
Дата: 27.02.02 13:07
Оценка:
Здравствуйте RS, Вы писали:

RS>что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита

RS>или использовать mutex?
Если ты не будешь играться с директивой "#pragma pack", то
все будет выровнено на такую границу само по себе — то есть — не надо будет
никаких дополнительных телодвижений.
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[2]: InterlockedIncrement vs. Mutex
От: RS Земля ICQ: 148844272
Дата: 27.02.02 13:11
Оценка:
Здравствуйте TepMuHyc, Вы писали:

TMH>Здравствуйте RS, Вы писали:


RS>>что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита

RS>>или использовать mutex?
TMH>Если ты не будешь играться с директивой "#pragma pack", то
TMH>все будет выровнено на такую границу само по себе — то есть — не надо будет
TMH>никаких дополнительных телодвижений.

Мой объект выделяется динамически, т.е. адрес моего счетчика определяется не прагмами, а тем, как производится выделение памяти (кратно ли 4).
Re[2]: InterlockedIncrement vs. Mutex
От: Кодт Россия  
Дата: 27.02.02 13:13
Оценка:
Здравствуйте TepMuHyc, Вы писали:

TMH>Здравствуйте RS, Вы писали:


RS>>что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита

RS>>или использовать mutex?
TMH>Если ты не будешь играться с директивой "#pragma pack", то
TMH>все будет выровнено на такую границу само по себе — то есть — не надо будет
TMH>никаких дополнительных телодвижений.

Надо полагать, мутекс займет у операционной системы всяко больше чем 32-4 байта, а кроме того, InterlockedXXcrement — это одна машинная инструкция, а вызов функций мутекса — огого (да еще и переход в 0 кольцо ядра).
Перекуём баги на фичи!
Re[3]: InterlockedIncrement vs. Mutex
От: Аноним  
Дата: 27.02.02 13:21
Оценка:
Здравствуйте Кодт, Вы писали:

К>Здравствуйте TepMuHyc, Вы писали:


TMH>>Здравствуйте RS, Вы писали:


RS>>>что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита

RS>>>или использовать mutex?
TMH>>Если ты не будешь играться с директивой "#pragma pack", то
TMH>>все будет выровнено на такую границу само по себе — то есть — не надо будет
TMH>>никаких дополнительных телодвижений.

К>Надо полагать, мутекс займет у операционной системы всяко больше чем 32-4 байта, а кроме того, InterlockedXXcrement — это одна машинная инструкция, а вызов функций мутекса — огого (да еще и переход в 0 кольцо ядра).


Поясните, пожалуйста:
а) одна машинная инструкция (call или Вы знаете, как устроен InterlockedXXcrement)?
б) Мутех плох, но хитрым способом выделять память под объект — лучше?

Прошу извинения, что использую слово "лучше", но не задал критерия. Таковым критерием является минимум геморроя при программизме.
Re[3]: InterlockedIncrement vs. Mutex
От: TepMuHyc  
Дата: 27.02.02 13:27
Оценка:
Здравствуйте RS, Вы писали:

RS>Мой объект выделяется динамически,

Куль.

RS>т.е. адрес моего счетчика определяется не прагмами,

Прагмами определяется смещение твоего счетчика в обьекте...

RS>а тем, как производится выделение памяти (кратно ли 4).

Кратно-кратно — не веришь — проверь.

ЗЫ. Между прочим, в ATL подсчет ссылок для многониточных контролов сделан
именно через InterlockedIncrement()...
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[4]: InterlockedIncrement vs. Mutex
От: RS Земля ICQ: 148844272
Дата: 27.02.02 13:36
Оценка:
Здравствуйте TepMuHyc, Вы писали:

TMH>Здравствуйте RS, Вы писали:


RS>>Мой объект выделяется динамически,

TMH>Куль.

RS>>т.е. адрес моего счетчика определяется не прагмами,

TMH>Прагмами определяется смещение твоего счетчика в обьекте...

RS>>а тем, как производится выделение памяти (кратно ли 4).

TMH>Кратно-кратно — не веришь — проверь.

TMH>ЗЫ. Между прочим, в ATL подсчет ссылок для многониточных контролов сделан

TMH>именно через InterlockedIncrement()...

1. Есть ли гарантии, что выделение памяти ВСЕГДА производится по адресам, кратным 4 (имею ввиду не VirtualAlloc, а malloc, new, HeapAlloc)?
2. Под Windows 95 MSDN не гарантирует, что InterlockedXXcrement вернет новое значение счетчика, а в ATL оно смело возвращается простым смертным. Корректно ли?
Re: InterlockedIncrement vs. Mutex
От: stringo Россия www.metaquotes.ru
Дата: 27.02.02 13:58
Оценка:
Здравствуйте RS, Вы писали:

RS>Делаю на API COM-сервер, к которому возможно обращение из нескольких потоков одного процесса. По идее, внутренний счетчик, модифицируемый методами AddRef и Release, должен быть доступен только одному потоку. Можно использовать mutex, но узнал об интересных функциях InterlockedIncrement и InterlockedDecrement. В описании этих функций указано, что на многопроцессорных машинах адрес счетчика должен быть выровнен на границу 32 бита. А теперь, внимание, вопрос: что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита или использовать mutex?


Начнём с того, что в твоей постановке мьютекс нафик не нужен! Зачем использовать объект ядра, управляемый из разных процессов, когда есть простая критическая секция, как раз и заточенная для синхронизации доступа из разных потоков одного процесса?
Тебе не надо обеспечивать выравнивание ком-объекта на границу 32 бит. гыыы. Он у тебя выровняецца на границу страницы памяти. Тебе нужно обеспечивать выравнивание счётчика. Если ты не используешь pragma pack меньше 4, и если твой счётчик имеет тип int, тогда ваще ничё обеспечивать не надо. Он у тебя и так будет на нужной тебе границе.
Так что используй себе спокойно InterlockedIncrement/Decrement и не заморачивайся.
- деструктора вызывали?
Re[2]: InterlockedIncrement vs. Mutex
От: Аноним  
Дата: 27.02.02 14:09
Оценка:
Здравствуйте stringo, Вы писали:

S>Начнём с того, что в твоей постановке мьютекс нафик не нужен! Зачем использовать объект ядра, управляемый из разных процессов, когда есть простая критическая секция, как раз и заточенная для синхронизации доступа из разных потоков одного процесса?


Критическая секция — это мутекс, не обеспечивающий очередности доступа, а только лишь "честное" распределение доступа.

S>Тебе не надо обеспечивать выравнивание ком-объекта на границу 32 бит. гыыы. Он у тебя выровняецца на границу страницы памяти. Тебе нужно обеспечивать выравнивание счётчика. Если ты не используешь pragma pack меньше 4, и если твой счётчик имеет тип int, тогда ваще ничё обеспечивать не надо. Он у тебя и так будет на нужной тебе границе.


Не pragma pack меня беспокоет, а адрес, возвращаемый new/malloc/HeapAlloc. Если бы были гарантии, что он ВСЕГДА кратен 4, то я спокоен, и вопрос снят.

S>Так что используй себе спокойно InterlockedIncrement/Decrement и не заморачивайся.

Покой нам только снится.
Re[3]: InterlockedIncrement vs. Mutex
От: stringo Россия www.metaquotes.ru
Дата: 27.02.02 15:08
Оценка:
Здравствуйте Аноним, Вы писали:

А>Критическая секция — это мутекс, не обеспечивающий очередности доступа, а только лишь "честное" распределение доступа.

А мужики-то не знают!

critical section
An object that protects a section of code from being accessed by more than one thread. A critical section is limited to only one process or dynamic-link library (DLL) and cannot be shared with other processes.

mutex object
An interprocess synchronization object whose state is set to signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex object.

Про какую очерёдность доступа идёт речь?
Единственная разница между критической секцией и мьютексом — пределы одного процесса/межпроцессное взаимодействие. и фсё!

А>Не pragma pack меня беспокоет, а адрес, возвращаемый new/malloc/HeapAlloc. Если бы были гарантии, что он ВСЕГДА кратен 4, то я спокоен, и вопрос снят.

ВСЕГДА кратен 4. Я даже больше скажу — всегда кратен 16.
вот тебе цитата из "Managing Heap Memory in Win32" by Randy Kath (Microsoft Developer Network Technology Group)
"Similar to the global and local memory functions, the heap memory functions have a minimum 16-byte granularity and the same overhead on memory allocations."

Это вообще-то соответствует плюсовому стандарту
5.3.4 New [expr.new]
...
13The allocation function shall either return null or a pointer to a
block of storage in which space for the object shall have been
reserved. [Note: the block of storage is assumed to be appropriately
aligned and of the requested size. The address of the created object
will not necessarily be the same as that of the block if the object is
an array. ]
(примечание: предполагаецца, что блок памяти должен быть соответствующим образом выровнен бла-бла-бла)

А вот терь про pragma pack, которая тебя не волнует. если ты описал какую нить структуру, а перед этим сказал, что надо "упаковывать" на границу байта, то у тебя гарантированно не будет промежутков памяти между членами структуры. а вот терь представь распределил ты для неё память и начинаешь доступацца к членам. вот что может быть
0000: char cMember1;
0001: int nMember2; — приплыли.
при умолчательной границе 8 байтов
0000: char cMember1;
0008: int nMember2; — 7 байт не используюцца никак, зато граница целых 8 байт!

так штааа.
- деструктора вызывали?
Re: InterlockedIncrement vs. Mutex
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 27.02.02 15:39
Оценка:
Здравствуйте RS, Вы писали:

RS>Делаю на API COM-сервер, к которому возможно обращение из нескольких потоков одного процесса. По идее, внутренний счетчик, модифицируемый методами AddRef и Release, должен быть доступен только одному потоку. Можно использовать mutex, но узнал об интересных функциях InterlockedIncrement и InterlockedDecrement. В описании этих функций указано, что на многопроцессорных машинах адрес счетчика должен быть выровнен на границу 32 бита. А теперь, внимание, вопрос: что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита или использовать mutex?


Mutex использовать в этой ситуации — неоправданное расточительство.

По умолчанию в настройках проекта в VC++ 6.0 установлено выравнивание на 8 байт. Таким образом, каждый член класса или структуры будет выровнян на границу 64 бит, что удовлетворит требованиям документации.

Как правильно заметил ТерМиНус, если ты не будешь играться с прагмами, то у тебя все получится и так. Но, если ты не уверен в том, какое выравнивание включено, либо используешь сторонние библиотеки (они потенциально могут это выравнивание поменять), либо ты просто параноик (я такой, и многие мои знакомые, которые не любят сюрпризов на многопроцессорных машинах, на которых выравнивание и сказывается), или еще какие причины присутствуют, советую делать следующее: все классы/структуры, в которых есть данные, критичные к выравниванию стоит обрамлять следующими строками:
#include <pshpack8.h>
...
// текст класса
...
#inlcude <poppack.h>

Результатом явится зашитие прямо в код выравнивания, и никакие уже установки среды не выведут твой код из равновесия.

PS: Да, кстати, все это относится к компилятору VC++, поэтому указанные выше строки стоит обрамлять
#ifdef _MSC_VER
#include <pshpack8.h>
#endif
...
и во втором случае тоже не забыть.

С уважением
Алексей Кирдин
Re[3]: InterlockedIncrement vs. Mutex
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 27.02.02 15:45
Оценка:
Здравствуйте Аноним, Вы писали:

А>Не pragma pack меня беспокоет, а адрес, возвращаемый new/malloc/HeapAlloc. Если бы были гарантии, что он ВСЕГДА кратен 4, то я спокоен, и вопрос снят.


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

С уважением
Алексей Кирдин
Re[5]: InterlockedIncrement vs. Mutex
От: TepMuHyc  
Дата: 27.02.02 16:25
Оценка:
Здравствуйте RS, Вы писали:

RS>1. Есть ли гарантии, что выделение памяти ВСЕГДА производится по адресам, кратным 4

RS>(имею ввиду не VirtualAlloc, а malloc, new, HeapAlloc)?
Явной гарантии тебе, конечно, никто не даст, но на практике можно считать что
блоки хипа выровнены на 32 бита.

RS>2. Под Windows 95 MSDN не гарантирует, что InterlockedXXcrement вернет

RS>новое значение счетчика, а в ATL оно смело возвращается простым смертным. Корректно ли?
Там гарантируется что InterlockedXXcrement вернет нулевое значение если в результате вызова получен нуль и ненулевое — если нет. Для AddRef() и Release() вполне достаточно. Что же касается значений которые они возвращают (цитата из документации) "is meant to be used for diagnostic/testing purposes only, because, in certain situations, the value may be unstable."
____________________
God obviously didn't debug, hasn't done any maintenance, and no documentation can be found. Truly amateur work.
Re[6]: InterlockedIncrement vs. Mutex
От: Alex Fedotov США  
Дата: 27.02.02 17:56
Оценка:
Здравствуйте TepMuHyc, Вы писали:

RS>>1. Есть ли гарантии, что выделение памяти ВСЕГДА производится по адресам, кратным 4

RS>>(имею ввиду не VirtualAlloc, а malloc, new, HeapAlloc)?
TMH>Явной гарантии тебе, конечно, никто не даст, но на практике можно считать что
TMH>блоки хипа выровнены на 32 бита.

Даст, даст. "The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object." Для x86 это означает выравнивание на 8 байт, что на самом деле и наблюдается.
-- Alex Fedotov
Re[4]: InterlockedIncrement vs. Mutex
От: Alex Fedotov США  
Дата: 27.02.02 18:01
Оценка:
Здравствуйте Аноним, Вы писали:

А>Поясните, пожалуйста:

А>а) одна машинная инструкция (call или Вы знаете, как устроен InterlockedXXcrement)?

__declspec(naked)
LONG __stdcall InterlockedIncrement(
    IN LONG volatile * p
    )
{ __asm {
    mov       ecx, [esp + 4]
    mov       eax, 1
    lock xadd [ecx], eax
    inc       eax
    ret       4
} }


Это если нужно корректно возвращать предыдущее значение.

А>б) Мутех плох, но хитрым способом выделять память под объект — лучше?


Не нужно никакого хитрого способа.
-- Alex Fedotov
Re: InterlockedIncrement vs. Mutex
От: RS Земля ICQ: 148844272
Дата: 04.03.02 11:31
Оценка:
Здравствуйте RS, я писал:

RS>Делаю на API COM-сервер, к которому возможно обращение из нескольких потоков одного процесса. По идее, внутренний счетчик, модифицируемый методами AddRef и Release, должен быть доступен только одному потоку. Можно использовать mutex, но узнал об интересных функциях InterlockedIncrement и InterlockedDecrement. В описании этих функций указано, что на многопроцессорных машинах адрес счетчика должен быть выровнен на границу 32 бита. А теперь, внимание, вопрос: что легче, обеспечить выравнивание COM-объекта при создании на границу 32 бита или использовать mutex?


Всем спасибо, убедили использовать InterlockedXXcrement. Адрес, возвращаемый malloc, new и прочими, выровнен на 32 бита как минимум, смещение поля в структуре тоже. Так что все должно работать.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.