この質問は、ACEミューテックスの使用についてです。以下は、非常に長い最小限の例です。ACEミューテックスはどのように機能し、ACEスレッドミューテックスは異なる動作をしますか?
コードはいくつかのスレッドを開始し、10秒後に停止します。それぞれのスレッドは、ミューテックスを取得しようとし、終了するまでそれを保持します。スレッドには2種類あります。第1の種類はグローバル変数を使用し、第2の種類はローカル変数を使用します。すべてのmutexは同じ名前です。スレッドは単一のプロセスを共有しているので、私はミューテックスを取得し、他のスレッドはこのスレッドが終了するまで待たなければならないと考えています。
観測:グローバルミューテックスは常に期待どおりに機能しますが、ACE_Thread_MutexとACE_Recursive_Thread_Mutexはローカル変数として使用すると失敗します。ローカルオブジェクトは、共有名にもかかわらず、明確なミューテックスであるように見えます。何故ですか?プロセス・ミューテックスと同様に動作するスレッド・ミューテックスはありますか?私はWindows上でACEを使用することに言及する必要があります。
私の2番目の質問は、ミューテックスがオブジェクトかオブジェクトへのポインタかどうかです。行動に違いはありますか?もちろん、ポインタは共有できますが、オブジェクトは扱いが簡単です。したがって、私はオブジェクトを好むが、スレッドミューテックスはプロセスミューテックスのようには動作しないように見える。
ありがとうございました。
PS:スレッドIDの前にプロセスIDを持つプロセス・ミューテックスを使用して、いつでもスレッド・ミューテックスをエミュレートできます。これは私の質問が目指すものではありません。
#include <iostream>
#include <sstream>
#include <ace/Process_Mutex.h>
#include <ace/Task.h>
#include <ace/Semaphore.h>
#define LOG(msg) std::cout << msg << std::endl;
#define NAME_MUTEX_THREAD "MY_UNIQUE_MUTEX"
// switch between different mutex types
// #define MUTEX_DECL(var, name) ACE_Thread_Mutex var(name);
// #define MUTEX_DECL(var, name) ACE_Recursive_Thread_Mutex var(name);
#define MUTEX_DECL(var, name) ACE_Process_Mutex var(name);
// #define MUTEX_DECL(var, name) ACE_Semaphore var(1, USYNC_THREAD, name);
// #define MUTEX_DECL(var, name) ACE_Semaphore var(1, USYNC_PROCESS, name);
ACE_Thread_Manager * g_pThreadManager;
MUTEX_DECL(g_oMutex, NAME_MUTEX_THREAD);
using namespace std;
std::string getThreadLogPrefix(void)
{
ACE_thread_t thisThread = ACE_OS::thr_self();
const int iProcessID = ACE_OS::getpid();
const int iThreadID = thisThread;
ostringstream convert;
convert <<"P"<<iProcessID<<"T"<<iThreadID;
return convert.str();
}
ACE_THR_FUNC_RETURN threadLocalMutexRace(void * par)
{
const ACE_thread_t thisThread = ACE_OS::thr_self();
const string strLog = getThreadLogPrefix() + "_threadLocalMutexRace: ";
MUTEX_DECL(oMutex, NAME_MUTEX_THREAD);
LOG(strLog<<"Start");
LOG(strLog<<"Try to acquire mutex");
int irc = oMutex.acquire();
if (irc == -1) {
LOG(strLog<<"Mutex not acquired (code "<<irc<<").");
return 0;
}
LOG(strLog<<"Mutex acquired (code "<<irc<<").");
while(ACE_Thread_Manager::instance()->testcancel(thisThread) == 0){
;
}
LOG(strLog<<"Stop");
oMutex.release();
LOG(strLog<<"Mutex released.");
return 0;
}
ACE_THR_FUNC_RETURN threadMutexRace(void * par)
{
const ACE_thread_t thisThread = ACE_OS::thr_self();
const string strLog = getThreadLogPrefix() + "_threadMutexRace: ";
LOG(strLog<<"Start");
LOG(strLog<<"Try to acquire mutex");
int irc = g_oMutex.acquire();
if (irc == -1) {
LOG(strLog<<"Mutex not acquired (code "<<irc<<").");
return 0;
}
LOG(strLog<<"Mutex acquired (code "<<irc<<").");
while(ACE_Thread_Manager::instance()->testcancel(thisThread) == 0){
;
}
LOG(strLog<<"Stop");
g_oMutex.release();
LOG(strLog<<"Mutex released.");
return 0;
}
int main(int argc, char * argv[])
{
ACE::init();
g_pThreadManager = new ACE_Thread_Manager();
const unsigned int uiNumThreadMutexRace = 3;
if (g_pThreadManager)
{
LOG("*******************************************************************");
LOG("Start threads...");
for (unsigned int i = 0; i < uiNumThreadMutexRace; ++i)
{
g_pThreadManager->spawn((ACE_THR_FUNC)threadMutexRace, nullptr);
}
for (unsigned int i = 0; i < uiNumThreadMutexRace; ++i)
{
g_pThreadManager->spawn((ACE_THR_FUNC)threadLocalMutexRace, nullptr);
}
ACE_OS::sleep(10);
LOG("Stop threads...");
g_pThreadManager->cancel_all();
g_pThreadManager->wait();
LOG("All threads stopped.");
LOG("*******************************************************************");
}
delete g_pThreadManager;
g_pThreadManager = nullptr;
return 0;
}