Почему метод TMutex Acquire () не блокирует мьютекс? - PullRequest
1 голос
/ 13 октября 2011

Пока у меня есть этот код:

****SimpleForm.h****
class TForm1 : public TForm
{
__published:    // IDE-managed Components
    TMemo *Memo1;
    TButton *Button1;
    void __fastcall Button1Click(TObject *Sender);
private:    // User declarations
    TMutex *mtx;
public:     // User declarations
    __fastcall TForm1(TComponent* Owner);
};

****SimpleForm.cpp****
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    mtx = new TMutex(true);
    WorkerThread *wt = new WorkerThread(false, mtx);
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    mtx->Acquire();
        Memo1->Lines->Add("Locked...");
    mtx->Release();
}

****WorkerThread.h****
class WorkerThread : public TThread
{
private:
    TMutex *mtx;
protected:
    void __fastcall Execute();
public:
    __fastcall WorkerThread(bool CreateSuspended, TMutex *mtx);
    void __fastcall CheckLock();
};
****WorkerThread.cpp****
__fastcall WorkerThread::WorkerThread(bool CreateSuspended, TMutex *mtx)
    : TThread(CreateSuspended)
{
    this->mtx = mtx;
}

void __fastcall WorkerThread::Execute()
{
    while(true){
        Sleep(1000);
        Synchronize(CheckLock);
    }

}

void __fastcall WorkerThread::CheckLock(){
    this->mtx->Acquire();
    Form1->Memo1->Lines->Add("Locked from thread");
    //this->mtx->Release();
}

Проблема в том, что mtx->Acquire() не блокирует мьютекс, когда я комментирую mtx->Release(), во время выполнения ничего не меняется, оба потока могут получить доступ к одному и тому же общему ресурсу одновременно, ведь это не то, что мне нужно. Я использовал p_threads в среде Linux, и когда мьютекс заблокирован, другие потоки ожидают его доступности. Как я могу достичь того же результата, используя C ++ CodeGear 2009?

1 Ответ

0 голосов
/ 13 октября 2011

Что-то еще является объяснением вашей проблемы, потому что TMutex::Acquire действительно получает блокировку объекта мьютекса. Реализация TMutex выглядит так:

procedure TMutex.Acquire;
begin
  if WaitFor(INFINITE) = wrError then
    RaiseLastOSError;
end;

procedure TMutex.Release;
begin
  if not ReleaseMutex(FHandle) then
    RaiseLastOSError;
end;

И WaitFor вызывает WaitForMultipleObjectsEx передачу дескриптора мьютекса.

Скорее всего, у вас есть несколько мьютексов, но я не могу сказать точно, так как не вижу весь ваш код.

Наконец, для синхронизации процессов вы должны предпочесть критическую секцию Windows, которая работает лучше, чем объект мьютекса Windows. Это TCriticalSection в RTL.


После вашего обновления легко увидеть, что происходит. Все использование замка происходит в основном потоке. Вы вызываете Synchronize, в результате чего метод выполняется в главном потоке. Если вы вызываете CheckLock непосредственно из вашего Execute метода, то вы зашли в тупик, как и предполагалось.

Вам необходимо использовать Synchronize для всех вызовов GUI. В целом он работает, сигнализируя основному потоку, что в очереди синхронизации что-то есть, а затем ожидая, пока основной поток завершит работу. Это асинхронный метод.

...