Вопрос по поводу потоков
1. чем отличаются _beginthreadex, AfxBeginThread и CreateThread? Ясное дело, что аргументами. Интересуют какие-то принципиальные отличия.
2. возможно ли в потоке, созданном какой-то из этих функций, обновлять данные (UpdateData()) в главном окне MFC-приложения?
3. возможно ли в MFC приложении запустить диалог в отдельном потоке? Если да, то как в двух словах.
1. чем отличаются _beginthreadex, AfxBeginThread и CreateThread? Ясное дело, что аргументами. Интересуют какие-то принципиальные отличия.
_beginthreadex - функция из библиотеки С\С++. AfxBeginThread - аналог из MFC, CreateThread - функция из WinApi. По идее в Windows и _beginthreadex и AfxBeginThread в конечном счете обращаются к CreateThread. Но _beginthreadex в отличие от CreateThread выполняет предварительную инициализацию библиотеки С\С++. Так что при альтернативе CreateThread или _beginthreadex многие авторы советуют остановить свой выбор на _beginthreadex.
Теоретически можно, но связано в рядом проблем.
3. возможно ли в MFC приложении запустить диалог в отдельном потоке? Если да, то как в двух словах.
Да. Но вероятнее всего придется использовать т.н. UI Thread. Т.е. потоки пользовательского интерфейса, а не просто рабочие.
Уточнение. Если не ошибаюсь, в стандартных библиотеках С\С++ нет такой функции. Это изобретение Microsoft. Таким образом, она может отсутствовать в компиляторах от других разработчиков. Ну и независимости от ОС поэтому наверно нет...
[QUOTE=nof]
2. возможно ли в потоке, созданном какой-то из этих функций, обновлять данные (UpdateData()) в главном окне MFC-приложения?
Теоретически можно, но связано в рядом проблем.[/QUOTE]
А подробнее? :)
Проблема заключается в том, что в моём приложении отдельный поток будет получать данные и должен их как-то отображать на форму. Но дело в том, что данные на форме обновлять некому..
дело в том, что я ей и пользуюсь. А тему создал, т.к. хочу найти решение по проблеме обновления данных на форме из другого потока..
добавлено:
ааа, только что идея появилась для обновления просто WM_TIMER использовать :D
В данном случае можно использовать сообщения. Если данные изменились в рабочем потоке, то он просто отправляет диалогу сообщение с требованием обновить.
Проблема заключается в том, что в моём приложении отдельный поток будет получать данные и должен их как-то отображать на форму. Но дело в том, что данные на форме обновлять некому..
А поподробней проблема будет заключаться в том, что нельзя будет просто передать второму потоку скажем указатель на CWnd и использовать его для изменения данных. Причина в т.н. Handle map, которыми MFC пользуется для перевода из HWND в CWnd. Так вот эти таблицы уникальны для каждого потока. Не найдя подходящий HWND для переданного CWnd, MFC будет "ругаться". Самое обидное заключается в том, что даже не прибегая к этому нехорошему способу (передачи CWnd), а пытаясь решить это окольными путями вы скорее всего тоже получите кучу assert'ов.
Вообщем самый правильный путь - это не пытаться из потока, выбирающего данные, напрямую обращаться к окнам или элементам управления главного окна. Наверное более правильным будет использовать этот поток только как источник данных для первичного потока (предположим с помощью очередей или посылки оконных сообщений), а уже все обновление на форме возложить исключительно на первичный поток.
типа того:
{
CEdit *edit;
CWnd *wnd;
.....
}Params;
....
//перед вызовом потока в классе главного окна:
Params *param = new Params;
param->edit = this->edit1;
param->wnd = this;
CreateThread (NULL, 0, MyThread, (LPVOID)param, NULL, NULL);
DWORT WINAPI MyThread (LPVOID pParam)
{
Param *p = (Param*)pParam;
while(....)
{
p->edit->SetWindowText("BlaBla");
p->wnd->SetWindowText(SomText);
}
}
Ну вот. Опять мы с oxotnik333 не сошлись во мнении. :D
Использование такого способа в Debug версии - скорее всего будет выдавать кучу assert'ов. В release версии - возможно будет работать, а возможно и нет, все зависит от вызываемых функций.
Использование такого способа в Debug версии - скорее всего будет выдавать кучу assert'ов. В release версии - возможно будет работать, а возможно и нет, все зависит от вызываемых функций.
Вот веришь нет, сделал точно так же как и написал, все работает почему то...
Могу исходники выложить
Могу исходники выложить
Верю. :)
Не спорю, но я же говорю, раз на раз. Вот допустим такой код
wnd->GetParentFrame();
в Debug'е "ругнется" assert'ом. А в релизе просто вернет NULL.
Просто я не сторонник подобного метода, так как при расширении кода могут возникнуть проблемы, на исправление которых может уйти слишком много времени. Поэтому по-моему лучше заранее потратить немного больше сил, но написать расширяемый код.
[OFFTOP]
Сталкивался однажды, когда получил уже написанный довольно большой код с использованием CSocket и одного потока. Протокол передачи данных переписывать с нуля не хотелось, поэтому для решения определенной проблемы решил поиграться с CSocket в отдельном потоке. "Наигравшись" понял, что перепиши я протокол заново с нуля, ушло бы гораздо меньше времени. Зато опыт :)
Извините за offtop
[/OFFTOP]
enum {UM_THREAD_DONE = WM_USER + 1};
...
// Шлём из потока сообщение:
...
PostMessage(dialogHwnd, UM_THREAD_DONE, 0, 0);
...
// Обрабатываем в нужном окне
switch (message)
{
case UM_THREAD_DONE:
OnUmMessage(hwnd);
break;
enum {UM_THREAD_DONE = WM_USER + 1};
...
// Шлём из потока сообщение:
...
PostMessage(dialogHwnd, UM_THREAD_DONE, 0, 0);
...
// Обрабатываем в нужном окне
switch (message)
{
case UM_THREAD_DONE:
OnUmMessage(hwnd);
break;
Да, вот это отличный вариант. Спасибо!
Могу исходники выложить
Вопрос первоначально о функции UpdateData(). В debug режиме программа падает, если вызвать её из потока...
Вопрос первоначально о функции UpdateData(). В debug режиме программа падает, если вызвать её из потока...
В потоке можно вызывать любую ф-ю, другой вопрос будет ли она работать с валидными данными или будет брать битые указатели. Возможно она обращается не к валидным данным, тут уже надо смотреть весь алгоритм целиком.
ЗЫ: Через SendMessage можно сделать многое, но не все