C++ ACE互斥体是如何工作的?为什么ACE线程互斥体的工作方式不同?

C++ ACE互斥体是如何工作的?为什么ACE线程互斥体的工作方式不同?,c++,multithreading,mutex,ace,C++,Multithreading,Mutex,Ace,这个问题是关于ACE互斥体的使用。下面是一个相当长的最小示例,其工作原理如下: 代码启动几个线程,并在10秒后停止它们。每个线程都试图获取一个互斥体,并将其保留到其终止。有两种线程。第一类使用全局变量,而第二类使用局部变量。所有互斥体都有相同的名称。由于线程共享一个进程,我希望一个线程获得互斥,而其他线程必须等待该线程终止 观察:虽然全局互斥始终按预期工作,但如果用作局部变量,ACE_线程互斥和ACE_递归线程互斥将失败。尽管有共享名称,但本地对象似乎是不同的互斥对象。为什么呢?是否有一个线程互

这个问题是关于ACE互斥体的使用。下面是一个相当长的最小示例,其工作原理如下:

代码启动几个线程,并在10秒后停止它们。每个线程都试图获取一个互斥体,并将其保留到其终止。有两种线程。第一类使用全局变量,而第二类使用局部变量。所有互斥体都有相同的名称。由于线程共享一个进程,我希望一个线程获得互斥,而其他线程必须等待该线程终止

观察:虽然全局互斥始终按预期工作,但如果用作局部变量,ACE_线程互斥和ACE_递归线程互斥将失败。尽管有共享名称,但本地对象似乎是不同的互斥对象。为什么呢?是否有一个线程互斥体,其工作原理类似于进程互斥体。我应该提到我在Windows上使用ACE

我的第二个问题是互斥体应该是对象还是指向对象的指针。行为上有什么不同吗?当然,指针可以共享,而对象更容易处理。因此我更喜欢对象,但线程互斥体似乎不像进程互斥体那样工作

非常感谢您的一些见解

PS:我知道我总是可以使用带有前置进程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;
}
#包括
#包括
#包括
#包括
#包括

#define LOG(msg)std::cout该名称不是ACE线程互斥体的唯一标识符。您必须确保两个线程使用相同的ACE线程互斥实例,通过使用局部变量,这两个线程都有自己的实例,可以独立锁定。通常在C++中,将互斥体作为类成员放置,以便在该类的各种操作中使用它。我建议阅读第10章。

该名称不是ACE线程互斥体的唯一标识符。您必须确保两个线程使用相同的ACE线程互斥实例,通过使用局部变量,这两个线程都有自己的实例,可以独立锁定。通常在C++中,将互斥体作为类成员放置,以便在该类的各种操作中使用它。我建议您阅读。

的第10章,其中有几点需要记住

1) 每个线程都有自己的堆栈,这意味着每个线程都有自己的变量副本,包括互斥体

2) 只有当线程可以访问相同的内存地址时,互斥锁才能工作


您正在为每个线程创建一个锁,而在多个线程之间应该有一个锁

要记住几件事

1) 每个线程都有自己的堆栈,这意味着每个线程都有自己的变量副本,包括互斥体

2) 只有当线程可以访问相同的内存地址时,互斥锁才能工作

您正在为每个线程创建一个锁,而在多个线程之间应该有一个锁