【问题标题】:How to get pointer from another thread?如何从另一个线程获取指针?
【发布时间】:2010-09-17 13:19:28
【问题描述】:

让我们有以下类定义:

CThread::CThread ()
{
    this->hThread       = NULL;
    this->hThreadId     = 0;
    this->hMainThread   = ::GetCurrentThread ();
    this->hMainThreadId     = ::GetCurrentThreadId ();
    this->Timeout       = 2000; //milliseconds
}

CThread::~CThread ()
{
    //waiting for the thread to terminate
    if (this->hThread) {
        if (::WaitForSingleObject (this->hThread, this->Timeout) == WAIT_TIMEOUT)
            ::TerminateThread (this->hThread, 1);

        ::CloseHandle (this->hThread);
    }
}

//*********************************************************
//working method
//*********************************************************
unsigned long CThread::Process (void* parameter)
{

    //a mechanism for terminating thread should be implemented
    //not allowing the method to be run from the main thread
    if (::GetCurrentThreadId () == this->hMainThreadId)
        return 0;
    else {
                m_pMyPointer = new MyClass(...);
                // my class successfully works here in another thread
        return 0;
    }

}

//*********************************************************
//creates the thread
//*********************************************************
bool CThread::CreateThread ()
{

    if (!this->IsCreated ()) {
        param*  this_param = new param;
        this_param->pThread = this;
        this->hThread = ::CreateThread (NULL, 0, (unsigned long (__stdcall *)(void *))this->runProcess, (void *)(this_param), 0, &this->hThreadId);
        return this->hThread ? true : false;
    }
    return false;

}

//*********************************************************
//creates the thread
//*********************************************************
int CThread::runProcess (void* Param)
{
    CThread*    thread;
    thread          = (CThread*)((param*)Param)->pThread;
    delete  ((param*)Param);
    return thread->Process (0);
}

MyClass* CThread::getMyPointer() {
    return m_pMyPointer;
}

在主程序中,我们有以下内容:

void main(void) {
  CThread thread;
  thread.CreateThread();

  MyClass* myPointer = thread.getMyPointer(); 
  myPointer->someMethod(); // CRASH, BOOM, BANG!!!!
}

在使用 myPointer 的那一刻(在主线程中)它崩溃了。我不知道如何获取在另一个线程中分配的指向内存的指针。这真的可能吗?

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    所有线程都可以访问应用程序的内存空间。默认情况下,无论上下文如何,任何线程都可以看到任何变量(唯一的例外是声明为 __delcspec(thread) 的变量)

    由于比赛条件,您遇到了崩溃。您刚刚创建的线程在您调用 getMyPointer 时尚未开始运行。您需要在新创建的线程和原始线程之间添加某种同步。换句话说,原始线程必须等待,直到新线程向它发出它已创建对象的信号。

    【讨论】:

    • 你说得对,我绝对睡着了 :) 非常感谢!我将在下面发布更正后的代码作为答案。
    【解决方案2】:

    我正在努力了解您要做什么。对于像线程类这样的东西,它看起来过于复杂。你介意发布类定义吗?

    首先删除 C 风格的过程参数转换为 CreateThread():

    this->hThread = ::CreateThread (NULL, 0,&runProcess, (void *)(this_param), 0, &this->hThreadId);
    

    如果这不能编译你做错了什么! 从不强制转换函数指针!如果编译器抱怨你需要改变你的函数,不要试图抛弃错误!真的!你只会让自己变得更糟!如果你再这样做他们*会来你家做......让我们看看你喜欢它!说真的,不要再这样做了。

    顺便说一句,在 Process() 中,我认为这样做更合适:

    assert(::GetCurrentThreadId() == hThreadId);
    

    但是如果你声明它是私有的,它应该只能被你的 CThread 类访问,因此它不应该是一个问题。断言很好!

    *不清楚他们是谁,但很明显他们所做的一切都不会令人愉快!

    【讨论】:

      【解决方案3】:

      正如 Rob Walker 指出的那样 - 我真的错过了比赛条件。另外崩溃不是获取指针的时候,而是使用它的时候。

      一个简单的等待就完成了:

      MyClass* myPointer = thread.getMyPointer(); 
      
      while (myPointer == 0) 
      {
          ::Sleep(1000);
      }
      
      myPointer->someMethod(); // Working :)
      

      【讨论】:

      • 虽然添加睡眠似乎可以解决问题,但它仍然是一个潜在的错误。无法保证线程会被踢掉,并在 1s 内跑到正确的位置。唯一的保证将需要线程之间的显式信号。
      • 实际上,在这种特定情况下,您可以旋转(稍作休眠)等待返回的指针不为零。通常不是推荐的模式,但它会使其更安全,并且通常比显式睡眠更快。
      • 使用条件变量会更快。再加上您添加的代码甚至不起作用,您需要在循环中调用 getMyPointer 。即使这样,在 m_pMyPointer 上没有互斥锁或 volatile 也不能保证它会起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 1970-01-01
      • 1970-01-01
      • 2011-05-02
      相关资源
      最近更新 更多