C++ Builder XE4, 10.2 Tokyo > TMutex, TCriticalSection: thread affinity | TSemaphore: not thread affinity | semaphoreでのロックコード


動作環境
C++ Builder XE4
RAD Studio 10.2 Tokyo Update 2 (追記: 2018/01/05)

関連

C++ Builder > TMutex > { ロックされない例 | ロックされる例 } | TCriticalSection > 300msecの待ちではロックされる

link

上記のリンクではロックが期待通りではなかった。

stackoverflowで質問をしていたが、Remy Lebeauさんに詳細な回答をいただいた。

回答の概要
(解釈間違いがあるかもしれません

  • TMutex: thread affinityである
  • TCriticalSection: thread affinityである
  • TSemaphore: thread affinityでない
  • Thread affinityの場合、TTimerでのロックはきかない
  • これらより、TSemaphoreではTTimerのロックは可能
  • mutexはinter-thread同期として使う
  • TTimer2つではsingle threadとして動作するため、mutexはuseless
  • など

code

stackoverflowでTSemaphoreを使ったロック例を紹介いただいた。

Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------


HANDLE hSemaphore;


__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
}

__fastcall TForm1::~TForm1()
{
    if (hSemaphore)
        CloseHandle(hSemaphore);
}

void __fastcall TForm1::FormShow(TObject *Sender)
{
    hSemaphore = CreateSemaphore(NULL, 1, 1, NULL);
    if (hSemaphore == NULL) {
        OutputDebugString(L"failed to create semaphore");
    }

    Timer1->Enabled = false;
    Timer1->Interval = 1000; // msec
    Timer1->Enabled = true;

    Timer2->Enabled = false;
    Timer2->Interval =  200; // msec
    Timer2->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
    if (WaitForSingleObject(hSemaphore, 0) != WAIT_OBJECT_0) {
        return;
    }

    if (CHK_update->Checked) {
        String msg = L"Timer1 " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz");
        Memo1->Lines->Add(msg);
    }

    for(int loop=0; loop<10; loop++) {
        Application->ProcessMessages();
        Sleep(90); // msec
    }

    ReleaseSemaphore(hSemaphore, 1, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
    if (WaitForSingleObject(hSemaphore, 0) != WAIT_OBJECT_0) {
        return;
    }

    if (CHK_update->Checked) {
        String msg = L">>>Timer2 " + Now().FormatString(L"yyyy/mm/dd hh:nn:ss.zzz");
        Memo1->Lines->Add(msg);
    }

    ReleaseSemaphore(hSemaphore, 1, NULL);
}
//---------------------------------------------------------------------------

きちんとロックがかかった。

備考

mutex, critical section, semaphoreなどの機構についてはまだ学習度が浅い。