AfxBeginThread и InitInstance()
От: meier13  
Дата: 08.02.12 09:49
Оценка:
Хотелось бы получить пояснения про то, как работает макрос AfxBeginThread, и что на самом деле происходит, допустим есть класс


class CPrintThread : public CWinThread
{
public:
    afx_msg void OnWriteLog(WPARAM, LPARAM);
    int Temp();
    virtual BOOL InitInstance();
    virtual int ExitInstance();
protected:
    DECLARE_MESSAGE_MAP()
    DECLARE_DYNCREATE(CPrintThread)
private:
    int temp;
};

IMPLEMENT_DYNCREATE(CPrintThread, CWinThread)

BEGIN_MESSAGE_MAP(CPrintThread, CWinThread)
    ON_THREAD_MESSAGE(WM_USER + 1, OnWriteLog)
END_MESSAGE_MAP()

void CPrintThread::OnWriteLog(WPARAM wParam, LPARAM lParam)
{
}

int CPrintThread::Temp()
{
    return temp;
}

BOOL CPrintThread::InitInstance()
{
    temp = 10;
    return true;
}

int CPrintThread::ExitInstance()
{
    return CWinThread::ExitInstance();
}


и где в программе:


CPrintThread* m_tPrint;
m_tPrint = (CPrintThread*)(AfxBeginThread(RUNTIME_CLASS(CPrintThread), THREAD_PRIORITY_BELOW_NORMAL, 0, 0));
int mytemp = m_tPrint->Temp();


поясните пожалуйста в каких потоках будут выполнятся функции InitInstance() и Temp(), и может ли получится так что mytemp окажется не равно 10 ?
Re: AfxBeginThread и InitInstance()
От: Hawk Россия  
Дата: 20.02.12 12:07
Оценка: 2 (1) +1
> поясните пожалуйста в каких потоках будут выполнятся функции InitInstance() и Temp(),

Вызов Temp() будет выполняться в главном потоке, InitInstance() — в дочернем.

> и может ли получится так что mytemp окажется не равно 10 ?


Теоретически — да. Для общения с потоком-наследником CWinThread лучше использовать сообщения, events и т.п. Напрямую вызывать методы и менять данные-члены — нельзя.
Re: AfxBeginThread и InitInstance()
От: Alexander G Украина  
Дата: 29.01.16 14:01
Оценка:
Здравствуйте, meier13, Вы писали:

CPrintThread* m_tPrint;
m_tPrint = (CPrintThread*)(AfxBeginThread(RUNTIME_CLASS(CPrintThread), THREAD_PRIORITY_BELOW_NORMAL, 0, 0));
int mytemp = m_tPrint->Temp();


M> и может ли получится так что mytemp окажется не равно 10 ?


Да запросто, поток завершается, экземпляр класса удаляется, и обращения к разыменованному m_tPrint непредсказуемы.

Воркэраунд:

CPrintThread* m_tPrint;
m_tPrint = (CPrintThread*)(AfxBeginThread(RUNTIME_CLASS(CPrintThread), THREAD_PRIORITY_BELOW_NORMAL, 0, CREATE_SUSPENDED));
m_tPrint->m_bAutoDelete = FALSE;
m_tPrint->ResumeThread();
int mytemp = m_tPrint->Temp();


У меня другой вопрос к знатокам MFC, зачем вообще такое странное поведение по умолчанию.
Русский военный корабль идёт ко дну!
Re: AfxBeginThread и InitInstance()
От: Evgeniy Skvortsov Россия  
Дата: 03.02.16 07:28
Оценка: -1
Здравствуйте, meier13, Вы писали:

M>Хотелось бы получить пояснения про то, как работает макрос AfxBeginThread, и что на самом деле происходит, допустим есть класс


Вообще, для рабочих потоков, которые что-то делают в фоне не используется наследник от CWinThread, а используется вариант с AFX_THREADPROC pfnThreadProc.
Вариант с наследником от CWinThread используется для запуска потока для взаимодействия с пользователем. Честно говоря никогда не использовал этот вариант.

То есть ты пишешь функцию которая будет выполняться в другом потоке, примерно так.

Если нужно заставить поток что-то сделать, используем события, например
Re[2]: AfxBeginThread и InitInstance()
От: Evgeniy Skvortsov Россия  
Дата: 03.02.16 08:07
Оценка: 1 (1)
Здравствуйте, Alexander G, Вы писали:

AG>Да запросто, поток завершается, экземпляр класса удаляется, и обращения к разыменованному m_tPrint непредсказуемы.


Если мне не изменяет мой склероз, то этот вариант ТС с созданием гуевого потока, в котором крутится цикл выборки и обработки сообщений.
Поток не завершится, пока не получит сообщение WM_QUIT

Если автор хотел вызвать функцию Temp, то надо примерно так делать:

// объявить функцию как для карты сообщений
afx_msg void Temp(WPARAM, LPARAM)
// добавить обработку в карту
BEGIN_MESSAGE_MAP(CPrintThread, CWinThread)
    ON_THREAD_MESSAGE(WM_USER + 1, OnWriteLog)
    ON_THREAD_MESSAGE(WM_USER + 2, Temp)
END_MESSAGE_MAP()

// в основном потоке
CPrintThread* m_tPrint = (CPrintThread*)(AfxBeginThread(RUNTIME_CLASS(CPrintThread), THREAD_PRIORITY_BELOW_NORMAL, 0, 0));
// Отсылка этого сообщения приведет к вызову функции Temp в дочернем потоке.
PostThreadMessage(m_tPrint->m_nThreadID, WM_USER + 2, 0, 0);


Для доступа к членам класса CPrintThread из основного потока и дочернего, нужно использовать синхронизацию, не помню что там в MFC используется.
Для завершения потока послать WM_QUIT
Если после завершения потока требуется обратиться к членам класса, то тогда потребуется вариант который ты привел где m_tPrint->m_bAutoDelete = FALSE;
Re[2]: AfxBeginThread и InitInstance()
От: Sergey_BG Россия  
Дата: 16.06.16 22:36
Оценка: -1
ES>Вообще, для рабочих потоков, которые что-то делают в фоне не используется наследник от CWinThread, а используется вариант с AFX_THREADPROC pfnThreadProc.
В МСДН написано чётко. Наследник этого класса можно запускать с гуём, и без него. Также он запускается с функцией.
Сергей
Re[3]: AfxBeginThread и InitInstance()
От: Sergey_BG Россия  
Дата: 16.06.16 22:42
Оценка:
ES>PostThreadMessage(m_tPrint->m_nThreadID, WM_USER + 2, 0, 0);

Не понимаю почему в такой простой функции все привязались к посылке сообщения для синхронизации? Здесь хватит обычного лока. Только доступ к значению переменной надо организовать через функцию.
Если это не подходит, то да, нужна посылка сообщения. Управление вернётся когда переменная уже изменена. Но здесь надо быть уверенным, что никто другой в это время её не изменяет.
Сергей
Re[4]: AfxBeginThread и InitInstance()
От: Sergey_BG Россия  
Дата: 17.06.16 21:55
Оценка:
Здравствуйте, Sergey_BG, Вы писали:
Забыл написать, что у посылки сообщения есть один существенный недостаток. Это то, что пока поток занят (не вызвал GetMessage) сообщение не будет доставлено. В то время как Lock будет ждать только изменение данной(или набора каких-то функций) переменной.
Сергей
Отредактировано 17.06.2016 21:55 Sergey_BG . Предыдущая версия .
Re[3]: AfxBeginThread и InitInstance()
От: Evgeniy Skvortsov Россия  
Дата: 23.06.16 21:43
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

ES>>Вообще, для рабочих потоков, которые что-то делают в фоне не используется наследник от CWinThread, а используется вариант с AFX_THREADPROC pfnThreadProc.

S_B>В МСДН написано чётко. Наследник этого класса можно запускать с гуём, и без него. Также он запускается с функцией.

Приведи пример где в этом есть смысл?
А минусы лепить я тоже умею.
Re[4]: AfxBeginThread и InitInstance()
От: Evgeniy Skvortsov Россия  
Дата: 23.06.16 21:51
Оценка:
Здравствуйте, Sergey_BG, Вы писали:

S_B>Не понимаю почему в такой простой функции все привязались к посылке сообщения для синхронизации? Здесь хватит обычного лока. Только доступ к значению переменной надо организовать через функцию.

S_B>Если это не подходит, то да, нужна посылка сообщения. Управление вернётся когда переменная уже изменена. Но здесь надо быть уверенным, что никто другой в это время её не изменяет.

Какого лока? ты вообще понимаешь что хочет ТС? Через какую функцию? Дружище, иди учи MFC и многопоточность!

Что за дичь ты написал?
Re[5]: AfxBeginThread и InitInstance()
От: Sergey_BG Россия  
Дата: 24.06.16 11:02
Оценка:
Здравствуйте, Evgeniy Skvortsov, Вы писали:
ES>Что за дичь ты написал?

Почему дичь? Я знаю MFC и многопоточность. Я понимаю, что спросил ТС.
Я написал следующее (может быть не совсем ясно):
1) у ТС есть функция GetTemp(). Если в ней и в функции SetTemp(...) поставить CSingleLock с СCriticalSection, то это заблокирует доступ второму потоку пока с переменной работает первый поток. И что самое интересное, если первый поток с переменной не работает, то не важно выполняет он, что либо, или нет. Метод будет вызван. В тоже время посылка сообщения другому потоку приведёт к тому, что SendMessage придётся ждать пока второй поток не войдет в режим ожидания очередного сообщения GetMessage etc. Именно в нём сработает SendMessage и только потом вернёт управление первому потоку. Что может быть достаточно долго, в зависимости от того, что делает поток. Т.е. плюс. Но есть один минус. Нужно быть уверенным, что поток не завершён. При посылке сообщения, правда тоже нужно знать, не завершился ли поток.
2) Есть ещё одна синхронизация которую нужно сделать. Это доступ к переменной потока. Так как по идее в любой момент поток может быть удалён (если стоит автоделит). Здесь тоже придётся принять некоторые меры.
Сергей
Отредактировано 24.06.2016 11:40 Sergey_BG . Предыдущая версия . Еще …
Отредактировано 24.06.2016 11:04 Sergey_BG . Предыдущая версия .
Re[4]: AfxBeginThread и InitInstance()
От: Sergey_BG Россия  
Дата: 24.06.16 11:07
Оценка:
ES>Приведи пример где в этом есть смысл?
Примеры приводить я не буду. Если я запускаю поток с ГУИ я запускаю WinTHread с ГУИ. Если нужно без гуи, то тоже запускаю без ГУИ. Как вариант можно вызвать с функцией, но это тоже самое, что и без гуи.

ES>А минусы лепить я тоже умею.

Кстати, если вы посмотрите кто вам "лепил" минус, то вы увидите, это был не я.
Сергей
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.