Как получить указатель из другого потока?

У нас есть следующее определение класса:

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
1 201
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

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

Вы абсолютно правы, и я абсолютно сплю :) Большое спасибо! Я отправлю исправленный код в качестве ответа ниже.

m_pGladiator 16.10.2008 19:14

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

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

MyClass* myPointer = thread.getMyPointer(); 

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

myPointer->someMethod(); // Working :)

Хотя добавление сна, похоже, решит проблему, это все еще скрытая ошибка. Нет никакой гарантии, что поток будет запущен и перейдет в нужное место в течение 1 секунды. Единственная гарантия потребует явного сигнала между потоками.

Rob Walker 16.10.2008 19:25

Фактически, в этом конкретном случае вы вращаете мог (с небольшим засыпанием), ожидая, что возвращаемый указатель будет ненулевым. В целом не рекомендуемый шаблон, но он сделает его безопаснее и в целом быстрее, чем явный сон.

Rob Walker 16.10.2008 19:26

Вместо этого использование условной переменной будет быстрее. Кроме того, ваш добавленный код даже не работает, вам нужно вызвать getMyPointer в цикле. Даже тогда, без блокировки мьютекса или volatile на m_pMyPointer нет гарантии, что он будет работать.

Greg Rogers 16.10.2008 19:34

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

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

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

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

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

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

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

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

Другие вопросы по теме