Как получить указатель из другого потока? - PullRequest
3 голосов
/ 16 октября 2008

Давайте получим следующее определение класса:

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 (в основном потоке) происходит сбой. Я не знаю, как получить указатель, который указывает на память, выделенную в другом потоке. Это действительно возможно?

Ответы [ 3 ]

11 голосов
/ 16 октября 2008

Пространство памяти для вашего приложения доступно для всех потоков. По умолчанию любая переменная видна любому потоку независимо от контекста (единственным исключением будут объявленные переменные __delcspec (thread))

Вы попали в аварию из-за состояния гонки. Поток, который вы только что создали, еще не начал работать в точке, где вы вызываете getMyPointer. Вам необходимо добавить какую-то синхронизацию между вновь созданным потоком и исходным потоком. Другими словами, исходящий поток должен ждать, пока новый поток не сообщит ему, что он создал объект.

0 голосов
/ 16 октября 2008

Я пытаюсь понять, что ты пытаешься сделать. Это выглядит слишком сложным для чего-то типа потока. Не могли бы вы опубликовать определение класса?

Начните с удаления приведения типа аргумента процесса к CreateThread ():

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

Если это не компилируется, вы делаете что-то не так! Никогда не приводить указатель на функцию! Если компилятор жалуется, что вам нужно изменить свою функцию, не пытайтесь отбрасывать ошибки! В самом деле! Вы только сделаете это хуже для себя! Если вы сделаете это снова , они * придут к вам домой и сделают ... Посмотрим, как вам это понравится! Серьезно, не делай этого снова.

Кстати, в Process () я думаю, что было бы более уместно сделать что-то вроде:

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

Но если вы объявите его закрытым, он все равно должен быть доступен только вашему классу CThread, и поэтому это не должно быть проблемой. Утверждения хороши, хотя!

* Непонятно, кто такие они , но понятно, что бы ни сделали они , это не будет приятно!

0 голосов
/ 16 октября 2008

Как указал Роб Уокер - я действительно пропустил условия гонки. Также сбой происходит не при получении указателя, а при его использовании.

Простое ожидание сделало свою работу:

MyClass* myPointer = thread.getMyPointer(); 

while (myPointer == 0) 
{
    ::Sleep(1000);
}

myPointer->someMethod(); // Working :)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...