Проблема с потоком

Тема в разделе "LANGS.C", создана пользователем Wereww, 10 ноя 2010.

  1. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    Доброго времени суток, прошу помочь с багом/кривизной рук.

    Ситауция такая, пишу многопоточную VCL DLL на CB6 - приложение из DLL запускаю в отдельном потоке (чтоб не мешало отработке других каллбэков и прочего), следующим образом:

    Код (Text):
    1. extern WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
    2.  
    3. DWORD WINAPI RunApp(LPVOID Param)
    4. {
    5.         try
    6.         {
    7.                  Application->CreateHandle();
    8.                  MainHWND = Application->Handle;
    9.                  WinMain(MainInstance,(void *)HPrevInst,CmdLine,CmdShow);
    10.         }
    11.         catch (Exception &exception)
    12.         {
    13.                  Application->ShowException(&exception);
    14.         }
    15.  
    16.     typedef void __fastcall (*TExitProc)();
    17.     if(System::ExitProc)((TExitProc)System::ExitProc)();
    18.  
    19.     if(hThreadApp)CloseHandle(hThreadApp);
    20.     hThreadApp=NULL;
    21.     MainHWND=NULL;
    22.    return 0;
    23. }
    24. //---------------------------------------------------------------------------
    25. void WINAPI StartAppThread(void *Param)
    26. {
    27.   DWORD Tid;
    28.   if(hThreadApp ||MainHWND)
    29.   {
    30.     SendMessage(Application->MainForm->Handle,WM_SYSCOMMAND,SC_RESTORE,0);
    31.     return;
    32.   }
    33.   hThreadApp=CreateThread(0,0,RunApp,(LPVOID)Param,0,&Tid);
    34.   SetThreadPriority(hThreadApp,THREAD_PRIORITY_NORMAL);
    35.   return;
    36. }
    Далее на форме имею TServerSocket с блокирующим сокетом, принимаю нить потомком от TServerClientThread и отрабатываю нить следующим образом:

    Код (Text):
    1. void __fastcall TDCEServerThread::UpdateCurrentInfo(void)
    2. {
    3.             //......отображение информации...
    4. }
    5. //---------------------------------------------------------------------------
    6. void __fastcall TDCEServerThread::ClientExecute(void)
    7. {
    8.    while (!Terminated && ClientSocket->Connected)
    9.    {
    10.       try
    11.       {
    12.          TWinSocketStream *pStream = new TWinSocketStream(ClientSocket, CLIENTWAITTIME);
    13.  
    14.          try
    15.          {
    16.             char buffer[BUFFERSIZE];
    17.  
    18.             memset( buffer, 0, sizeof(buffer) );
    19.  
    20.             //......обработка...
    21.  
    22.                 Synchronize(UpdateCurrentInfo);
    23.                 ClientSocket->Close();
    24.  
    25.             //......обработка...
    26.  
    27.          }
    28.          __finally
    29.          {
    30.             delete pStream;
    31.          }
    32.       }
    33.       catch (...)
    34.       {
    35.          HandleException();
    36.       }
    37.    }
    38.     FreeOnTerminate = true;
    39. }
    Но в момент вызова метода Synchronize - вываливается эксепшн - "CheckSynchronize called from thread $10A8, which is NOT the main thread.", как я понял баг мог возникнуть при таком запуске приложения через API, почитал парочку страниц про CheckSynchronize и WakeMainThread, но ничего так и не понял, в инете тоже все глухо...у кого какие предположения ?
     
  2. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Че-то я не понял почему, вы не читаете топик про сэпшены...
    [modnote=TermoSINteZ]Выбирайте выражения. Вам предупреждение.[/modnote]
     
  3. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    В том то и дело, что по этому вопросу мало чего есть в сети - а то что было уже прочитал, но никаких мыслей всеравно не пришло - разве что стартовать поток приложения в VCL.
     
  4. Master_B0

    Master_B0 New Member

    Публикаций:
    0
    Регистрация:
    3 фев 2008
    Сообщения:
    109
    CB 6 удали и поставь http://www.embarcadero.com/products/cbuilder полная поддержка win32API И уникода ! и будет все работать (если нет то надо бы выложить весь бы проект )! в старой версии от борлонда содержатся ошибки в компонентах !
     
  5. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    Спасибо за отклик - попробую перекомпилить на BDS 2009
     
  6. Master_B0

    Master_B0 New Member

    Публикаций:
    0
    Регистрация:
    3 фев 2008
    Сообщения:
    109
    Вот тут не правильно
    вам надо соединить к проекту Thread Object
    и внутри описать действия
    Код (Text):
    1. void __fastcall Tr::Execute()  
    2. {
    3.  
    4. ......
    5.  ваши действия  ...
    6. ......
    7.     Application->ProcessMessages();  // чтобы не было зависания формы ... если данные выводится на нее в потоке !
    8.     if(Terminated) break; // если нажали стоп ( Radar->Terminate(); ) брякаем ...
    9.  }
    запуск и стоп потока

    Код (Text):
    1.  Tr *Radar;
    2.  
    3.  //запуск
    4.  
    5.     Radar = new Scanner(true);
    6.     Radar->Priority = tpNormal;
    7.         Radar->Resume();
    8.  
    9.  //стоп
    10.      
    11.         Radar->Terminate();
    прежде чем делать много поточное преложенный на VCL почитайте http://rxlib.ru/WinLesson/bles2_1.htm


    ЗЫ

    Лучше сделать форму на VCL , а все действия работы с сетью написать на win32 winsock !
     
  7. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    Что и было проделано, дело в том что основной поток это DLL EP - форма со всем остальным (тоже VCL) второй - и из этого второго потока запускаются остальные - для отсылки данных каждому клиенту.
     
  8. Master_B0

    Master_B0 New Member

    Публикаций:
    0
    Регистрация:
    3 фев 2008
    Сообщения:
    109
    поток в потоке ?


    Код (Text):
    1.    while (!Terminated && ClientSocket->Connected) - это не поток это цикл
     
  9. Master_B0

    Master_B0 New Member

    Публикаций:
    0
    Регистрация:
    3 фев 2008
    Сообщения:
    109
    скинте весть проект будет более понятно в чем проблема по объяснениям вашим не могу понять
     
  10. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    Прошу прощения ) забыл кусочек кода - думаю будет более понятно где цикл а где поток -

    Код (Text):
    1. void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender,
    2.       TServerClientWinSocket *ClientSocket,
    3.       TServerClientThread *&SocketThread)
    4. {
    5.         SocketThread = new TDCEServerThread(false, ClientSocket);
    6. }
    Код (Text):
    1. class PACKAGE TDCEServerThread : public Scktcomp::TServerClientThread
    2. {
    3.    public:
    4.       __fastcall TDCEServerThread (bool CreateSuspended, TServerClientWinSocket* ASocket)
    5.          : Scktcomp::TServerClientThread(CreateSuspended, ASocket)
    6.          { CreateSuspended = false; KeepInCache=true; FreeOnTerminate=false; };
    7.  
    8.  
    9.       void __fastcall ClientExecute(void);
    10.       //void __fastcall UpdateCurrentInfo(void);
    11.  
    12. };
    Все работает идеально за исключением Synchronize, придётся провести ночь на codegear.com
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Synchronize работает только с потоком MainThreadID (в котором происходит загрузка dll). Ты же создаешь Application.Handle в доп.потоке и соотв-но WakeMainThread будит именно этот доп.поток и соотв-но CheckSynchronize в этом потоке обламывается.
    Простое решение - на шару установить в RunApp переменную MainThreadID = GetCurrentThreadID(). Однако приведет ли это к каким-то побочным эффектам или нет - не знаю, т.к. в этой запутанной VCL черт ногу сломит
     
  12. Wereww

    Wereww Дмитрий

    Публикаций:
    0
    Регистрация:
    13 июн 2009
    Сообщения:
    55
    Огромное спасибо за поддержку - впринципе судя по вашим суждениям я понимал это аналогично - но относительно WakeMainThread и CheckSynchronize - то никак немогу понять как они немогут работать в связанных классах - сделал аналогичный проэкт-игрушку треда-из-трэды (чистый VCL) чтоб повисло все - работает - даже с Synchronize - но в DLL никак...ТП BCB посоветовала включить MEMMGR.LIB - что и было описано в комментах длл-темплейта - не помогло...делал ручной вызов WakeMainThread и CheckSynchronize через VCL фэйс.....я уже хз как с этим бороться...
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Сам понял, что сказал ?
    Использование Synchronize в потоках dll вообще не предусмотрено. Между потоком из dll и основным потоком приложения Synchronize вообще не работает, т.к. при этом юзается несколько глобальных переменных (эвент, крит секция и список синхронизируемых методов), которые у приложения и у dll ес-но свои собственные и соотв-но приложение "видит" только свои переменные и "понятия не имеет" об аналогичных переменных в dll. Если же в dll создавать свой поток, "подменяющий" основной поток приложения (как ты делаешь в #1), то происходит облом CheckSynchronize, т.к. ID этого потока не равно значению переменной MainThreadID (устанавливаемое при старте dll при DLL_PROCESS_ATTACH).
    Поэтому либо попробуй на шару переустановить MainThreadID в RunApp (и смотри, не приведет ли это к каким-то другим багам), либо сразу забей на этот Synchronize и делай свою синхронизацию на SendMessage или эвентах и т.п. (по типу Synchronize)