Понимание TCriticalSection и Synchronize

Я хотел бы подтвердить здесь, правильно ли я понял, как работают TCriticalSection и Synchronize.

Насколько я знаю прямо сейчас Synchronize использует SendMessage (обновление: или, по крайней мере, использовал его в более старых версиях VCL, как указано в нескольких комментариях ниже), который приостанавливает выполнение текущего потока (а также любого другого потока), в отличие от PostMessage, который этого не делает и затем выполняет требуемую функцию (из основного потока). В некотором смысле SendMessage "останавливает" многопоточность при выполнении.

Но насчет TCriticalSection я не уверен. Скажем, например, я создаю что-то вроде этого:

// Global variables somewhere in my code any thread can access
boost::scoped_ptr<TCriticalSection> ProtectMyVarAndCallFnction(new TCriticalSection);
int MyVariable1;
void CallMyFunctionThatAlsoModifiesMoreStuff() { /* do even more here */ };


// Thread code within one of the threads
try {
    ProtectMyVarAndCallFnction->Acquire();
    MyVariable1++;
    CallMyFunctionThatAlsoModifiesMoreStuff();
    }
__finally {
    ProtectMyVarAndCallFnction->Release();
    }

Теперь у меня вопрос - как критический раздел «знает», что я защищаю MyVariable1 в этом случае, а также все, что вызываемая функция может изменить?

Если я правильно понял - это не так - и я обязан правильно вызвать Acquire () в любом потоке, который хочет изменить MyVariable1 или вызвать эту функцию (или выполнить любое из двух). Другими словами, я думаю о TCriticalSection как о пользовательском блоке, который определяет все, что я ему логически присвоил. Это может быть набор переменных или любая конкретная функция, если я вызываю Acquire () внутри всех потоков, которые могут писать в этот блок или использовать эту функцию. Например, «DiskOp» может быть моим именем TCriticalSection, который записывает на диск, «Интернет» может быть именем TCriticalSection, который вызывает функции, которые получают некоторые данные из Интернета. Я правильно понял?

Кроме того, в этом контексте всегда ли TCriticalSection должен быть глобальной переменной?


person Coder12345    schedule 03.12.2012    source источник
comment
Synchronize не использует SendMessage.   -  person kludg    schedule 03.12.2012
comment
@Serg Это есть в более старых версиях VCL   -  person David Heffernan    schedule 03.12.2012
comment
@DavidHeffernan - очень старые версии, Delphi 3 использовал SendMessage для реализации Synchronize.   -  person kludg    schedule 03.12.2012
comment
@Serg Delphi 5 тоже. Изменено в Delphi 6, по-видимому, потому, что SendMessage не работал в Linux.   -  person David Heffernan    schedule 03.12.2012


Ответы (1)


SendMessage приостанавливает выполнение текущего потока (а также любого другого потока).

Нет, это неверно. SendMessage ничего не приостанавливает. SendMessage просто синхронно доставляет сообщение. Функция не возвращается, пока сообщение не будет доставлено. То есть процесс окна целевого окна был выполнен. И поскольку процесс окна всегда вызывается в потоке, которому принадлежит окно, это означает, что вызывающий поток может потребоваться заблокировать, чтобы дождаться, пока поток, владеющий окном, не будет готов выполнить процедуру окна. Это определенно не приостанавливает все потоки в процессе.

Как критический раздел знает, что я защищаю MyVariable1?

Это не так. Только вы должны убедиться, что все виды использования MyVariable1, нуждающиеся в защите, защищены. Критическая секция - это форма мьютекса. Мьютекс гарантирует, что только один поток выполнения может удерживать мьютекс в любой момент времени.

Поскольку я вызываю Acquire() во всех потоках, которые могут писать в этот блок или использовать эту функцию.

Это тоже не совсем то. Фраза «внутри всех веток» - это заблуждение. Вы должны думать о «всех разделах кода, которые используют переменную».

Следовательно, всегда ли критическая секция должна быть глобальной переменной?

Нет, критическая секция может быть глобальной переменной. Но этого не должно быть.

person David Heffernan    schedule 03.12.2012
comment
Спасибо за этот ответ, это кое-что проясняет. Я предполагаю, что с SendMessage я спрашивал - если у меня есть основной поток + 2 дополнительных запущенных потока и я вызываю Synchronize из потока №1 для обновления материала в основном потоке, поток №1 остановится, пока не завершится Synchronize, но поток №2 все равно продолжит выполнение ? - person Coder12345; 03.12.2012