为什么 TMutex 方法 Acquire() 不锁定互斥体?

发布于 2024-12-09 18:43:50 字数 1573 浏览 0 评论 0原文

到目前为止,我有这段代码:

****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->Release() 时,mtx->Acquire() 没有锁定互斥锁,在运行时没有任何变化,两个线程可以同时访问相同的共享资源,这不是我想要的。我在Linux环境中使用p_threads,当互斥体被锁定时,其他线程等待它变得可用。如何使用 C++ CodeGear 2009 获得相同的结果?

So far I have this code:

****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();
}

The problem is, mtx->Acquire() does not lock a mutex, when I comment the mtx->Release(), nothing changes during runtime, both threads can access the same shared resource at the same time, witch is not what I want. I was using p_threads in Linux environment, and when the mutex is locked, other threads waits for it to become available. How can I achieve the same result using C++ CodeGear 2009 ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

乖乖 2024-12-16 18:43:50

其他的东西可以解释你的问题,因为 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 互斥对象更好。这就是 RTL 中的 TCriticalSection


更新后,很容易看到发生了什么。所有锁的使用都发生在主线程中。您调用 Synchronize 会导致该方法在主线程上执行。如果您直接从 Execute 方法调用 CheckLock,那么您将按预期死锁。

您需要对所有 GUI 调用使用 Synchronize。从广义上讲,它的工作原理是向主线程发出信号,告知同步队列中有某些内容,然后等待主线程完成工作。它是一种异步方法。

Something else is the explanation to your problem because TMutex::Acquire does indeed acquire a lock on the mutex object. The implementation of TMutex looks like this:

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

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

And WaitFor calls WaitForMultipleObjectsEx passing the mutex handle.

Most likely is that you actually have more than one mutex somehow but I can't tell for sure since I can't see all of your code.

Finally, for within process synchronisation you should prefer the Windows critical section which performs better than the Windows mutex object. That is TCriticalSection in the RTL.


Following your update it is easy to see what is happening. All use of the lock happens in the main thread. You call Synchronize which results in the method executing on the main thread. If you call CheckLock directly from your Execute method then you will deadlock as intended.

You need to use Synchronize for all GUI calls. It works, broadly, by signaling the main thread that there is something in the synchronize queue and then waiting until the main thread has completed the work. It is an asynchronous method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文