Доброго времени суток, прошу помочь с багом/кривизной рук. Ситауция такая, пишу многопоточную VCL DLL на CB6 - приложение из DLL запускаю в отдельном потоке (чтоб не мешало отработке других каллбэков и прочего), следующим образом: Код (Text): extern WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int); DWORD WINAPI RunApp(LPVOID Param) { try { Application->CreateHandle(); MainHWND = Application->Handle; WinMain(MainInstance,(void *)HPrevInst,CmdLine,CmdShow); } catch (Exception &exception) { Application->ShowException(&exception); } typedef void __fastcall (*TExitProc)(); if(System::ExitProc)((TExitProc)System::ExitProc)(); if(hThreadApp)CloseHandle(hThreadApp); hThreadApp=NULL; MainHWND=NULL; return 0; } //--------------------------------------------------------------------------- void WINAPI StartAppThread(void *Param) { DWORD Tid; if(hThreadApp ||MainHWND) { SendMessage(Application->MainForm->Handle,WM_SYSCOMMAND,SC_RESTORE,0); return; } hThreadApp=CreateThread(0,0,RunApp,(LPVOID)Param,0,&Tid); SetThreadPriority(hThreadApp,THREAD_PRIORITY_NORMAL); return; } Далее на форме имею TServerSocket с блокирующим сокетом, принимаю нить потомком от TServerClientThread и отрабатываю нить следующим образом: Код (Text): void __fastcall TDCEServerThread::UpdateCurrentInfo(void) { //......отображение информации... } //--------------------------------------------------------------------------- void __fastcall TDCEServerThread::ClientExecute(void) { while (!Terminated && ClientSocket->Connected) { try { TWinSocketStream *pStream = new TWinSocketStream(ClientSocket, CLIENTWAITTIME); try { char buffer[BUFFERSIZE]; memset( buffer, 0, sizeof(buffer) ); //......обработка... Synchronize(UpdateCurrentInfo); ClientSocket->Close(); //......обработка... } __finally { delete pStream; } } catch (...) { HandleException(); } } FreeOnTerminate = true; } Но в момент вызова метода Synchronize - вываливается эксепшн - "CheckSynchronize called from thread $10A8, which is NOT the main thread.", как я понял баг мог возникнуть при таком запуске приложения через API, почитал парочку страниц про CheckSynchronize и WakeMainThread, но ничего так и не понял, в инете тоже все глухо...у кого какие предположения ?
Че-то я не понял почему, вы не читаете топик про сэпшены... [modnote=TermoSINteZ]Выбирайте выражения. Вам предупреждение.[/modnote]
В том то и дело, что по этому вопросу мало чего есть в сети - а то что было уже прочитал, но никаких мыслей всеравно не пришло - разве что стартовать поток приложения в VCL.
CB 6 удали и поставь http://www.embarcadero.com/products/cbuilder полная поддержка win32API И уникода ! и будет все работать (если нет то надо бы выложить весь бы проект )! в старой версии от борлонда содержатся ошибки в компонентах !
Вот тут не правильно вам надо соединить к проекту Thread Object и внутри описать действия Код (Text): void __fastcall Tr::Execute() { ...... ваши действия ... ...... Application->ProcessMessages(); // чтобы не было зависания формы ... если данные выводится на нее в потоке ! if(Terminated) break; // если нажали стоп ( Radar->Terminate(); ) брякаем ... } запуск и стоп потока Код (Text): Tr *Radar; //запуск Radar = new Scanner(true); Radar->Priority = tpNormal; Radar->Resume(); //стоп Radar->Terminate(); прежде чем делать много поточное преложенный на VCL почитайте http://rxlib.ru/WinLesson/bles2_1.htm ЗЫ Лучше сделать форму на VCL , а все действия работы с сетью написать на win32 winsock !
Что и было проделано, дело в том что основной поток это DLL EP - форма со всем остальным (тоже VCL) второй - и из этого второго потока запускаются остальные - для отсылки данных каждому клиенту.
Прошу прощения ) забыл кусочек кода - думаю будет более понятно где цикл а где поток - Код (Text): void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender, TServerClientWinSocket *ClientSocket, TServerClientThread *&SocketThread) { SocketThread = new TDCEServerThread(false, ClientSocket); } Код (Text): class PACKAGE TDCEServerThread : public Scktcomp::TServerClientThread { public: __fastcall TDCEServerThread (bool CreateSuspended, TServerClientWinSocket* ASocket) : Scktcomp::TServerClientThread(CreateSuspended, ASocket) { CreateSuspended = false; KeepInCache=true; FreeOnTerminate=false; }; void __fastcall ClientExecute(void); //void __fastcall UpdateCurrentInfo(void); }; Все работает идеально за исключением Synchronize, придётся провести ночь на codegear.com
Synchronize работает только с потоком MainThreadID (в котором происходит загрузка dll). Ты же создаешь Application.Handle в доп.потоке и соотв-но WakeMainThread будит именно этот доп.поток и соотв-но CheckSynchronize в этом потоке обламывается. Простое решение - на шару установить в RunApp переменную MainThreadID = GetCurrentThreadID(). Однако приведет ли это к каким-то побочным эффектам или нет - не знаю, т.к. в этой запутанной VCL черт ногу сломит
Огромное спасибо за поддержку - впринципе судя по вашим суждениям я понимал это аналогично - но относительно WakeMainThread и CheckSynchronize - то никак немогу понять как они немогут работать в связанных классах - сделал аналогичный проэкт-игрушку треда-из-трэды (чистый VCL) чтоб повисло все - работает - даже с Synchronize - но в DLL никак...ТП BCB посоветовала включить MEMMGR.LIB - что и было описано в комментах длл-темплейта - не помогло...делал ручной вызов WakeMainThread и CheckSynchronize через VCL фэйс.....я уже хз как с этим бороться...
Сам понял, что сказал ? Использование Synchronize в потоках dll вообще не предусмотрено. Между потоком из dll и основным потоком приложения Synchronize вообще не работает, т.к. при этом юзается несколько глобальных переменных (эвент, крит секция и список синхронизируемых методов), которые у приложения и у dll ес-но свои собственные и соотв-но приложение "видит" только свои переменные и "понятия не имеет" об аналогичных переменных в dll. Если же в dll создавать свой поток, "подменяющий" основной поток приложения (как ты делаешь в #1), то происходит облом CheckSynchronize, т.к. ID этого потока не равно значению переменной MainThreadID (устанавливаемое при старте dll при DLL_PROCESS_ATTACH). Поэтому либо попробуй на шару переустановить MainThreadID в RunApp (и смотри, не приведет ли это к каким-то другим багам), либо сразу забей на этот Synchronize и делай свою синхронизацию на SendMessage или эвентах и т.п. (по типу Synchronize)