Страницы

Поиск по вопросам

среда, 5 февраля 2020 г.

Почему обнуляется переданный в поток указатель? CreateThread

#cpp #многопоточность


Здравствуйте! 
У меня есть 2 глобальных массива static TCHAR abc[32+1]; и  static TCHAR defa[32+1];,
объявлены в главном cpp, сразу после includ-ов.

Есть главная ф-ия, которая в свою очередь запускает функцию start():

//Main.cpp
    void WINAPI entryPoint() {
      start();
      while (true) { Sleep(3000); MessageBox(0,abc,0,0);} 
    }


Функция start заполняет массив определенным содержанием, а дальше запускает ф-ию(startThread),
которая находится уже в другом файле cpp, которая в свою очередь запускает поток с
помощью CreateThread:

//Main.cpp
    bool start() {
       lstrcpy(abc, _T("Hello")); 
       lstrcpy(defa, _T("How are you?"));
       startThread(abc);
       MessageBox(0,_T("Завершить функцию start?"));
    }

//Thread.cpp
struct PARAMS{
    TCHAR *abc;
    TCHAR *defa;
}

    void startThread(TCHAR *abc, TCHAR *defa) {
        PARAMS arr = { abc, defa };
        CreateThread(NULL, 0, &threadfunction, &arr, 0, NULL);

    }


Сама функция потока выглядит так:

//Thread.cpp
    DWORD WINAPI threadfunction(LPVOID arr) {
        PARAMS*PARR= (PARAMS*)arr;
       while (true) {
            MessageBox(0, PARR->abc, L"Thread 2", 0);
            MessageBox(0, PARR->defa, L"Thread 2", 0);
        }
    }


Проблема в том, что после того как завершается функция bool start() в главном потоке,
из abc и defa исчезают значения и поток начинает выдавать пустые сообщения, я не понимаю
почему это происходит. При чем, если не завершать функцию start(), т.е. не закрывать
мессагу  MessageBox(0,_T("Завершить функцию start?"));, то все нормально. Из главного
потока я по прежнему имею доступ к этим переменным, даже после завершения start(),
т.е. вот тут все нормально продолжает работать while (true) { Sleep(3000); MessageBox(0,abc,0,0);} 

Реализация на чистом WinApi, так что, другие варианты создания потоков не рассматриваю.
    


Ответы

Ответ 1



void startThread(TCHAR *abc, TCHAR *defa) { PARAMS arr = { abc, defa }; CreateThread(NULL, 0, &threadfunction, &arr, 0, NULL); } В любом случае передавать в функцию потока адрес локального объекта arr - очень нехорошо. Поток еще и запуститься как следует не успевает, а выделенная под arr память уже недействительна...

Ответ 2



после "PARAMS arr = { abc, defa }; CreateThread(NULL, 0, &threadfunction, &arr, 0, NULL);" надо подключиться к потоку и дождаться его завершения или PARAMS на new и освобождать внутри потока.

Ответ 3



Можно сделать так: void startThread(TCHAR *abc, TCHAR *defa) { PARAMS arr = new PARAMS{ abc, defa }; CreateThread(NULL, 0, &threadfunction, arr, 0, NULL); } И вызывать деструктор в функции потока. Еще лучше сделать так: void startThread(TCHAR *abc, TCHAR *defa) { std::thread thread{ [abs, defa]{ while (true) { MessageBox(0, abc, L"Thread 2", 0); MessageBox(0, defa, L"Thread 2", 0); } // delete[] abs; deletee[] defa; // Кто-то должен освобождать память, но цикл бесконечный. }}; thread.detach(); // Отпускаем поток в свободное плаванье. Ну или ждем завершения при помощи thread.join(); } Кроме того, по хорошему нужно завершить поток до завершения программы, т.к. иначе не все деструкторы будут вызваны. Ресурсы система, конечно, освободит, но в реальных проектах может потребоваться выполнить дополнительные действия, например, запись в log файлы. Для этого можно использовать механизм событий, или банально общие атомарные переменные (посмотрите в сторону std::atomic). Тогда вместо while(true) будет while(cond), и после завершения цикла можно освобождать ресурсы и совершать другие действия.

Комментариев нет:

Отправить комментарий