На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Передача сообщений между потоками WINAPI
    Здравствуйте!
    Есть следующая задача: написать многопоточное консольное приложение (использовать WinAPI), которое создаёт основной поток, тот в свою очередь создаёт несколько “подчиненных” потоков. Необходимо наладить обмен сообщениями между основным и подчинёнными потоками. Например, при получении сообщения от основного потока, подчинённые начинают построчно читать указанный текстовый файл и передавать сообщением в основной поток. Основной поток выводит строки из файла на экран.

    Написал следующий код:

    ExpandedWrap disabled
      #include <stdio.h>
      #include <conio.h>
      #include <iostream>
      #include <fstream>
      #include <string>
      #include <sstream>
      #include <Windows.h>
       
      using namespace std;
       
      //Messages:
      #define WM_READ_FILE        WM_APP+1
      #define WM_SEND_LINE        WM_APP+3
      #define WM_EOF              WM_APP+4
       
       
      DWORD WINAPI SlaveThreadFunc(LPVOID lpParam)
      {  
          DWORD MainThreadID=DWORD(lpParam);
          WPARAM CurrentID=(WPARAM)GetCurrentThreadId();
          MSG msg;
          bool fDone=false;
       
          while (!fDone)
          {
              //do something
              //...
       
              while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
              {
                  Sleep(100);
       
                  switch (msg.message)
                  {
                      case WM_READ_FILE:
                      {
                          stringstream stream;
                          stream << (char*)msg.lParam;
                          string file_path = stream.str();
       
                          ifstream file(file_path);
                          if(file.is_open())
                          {
                              string line;
                              while(getline(file, line))
                              {
                                  //Sleep(10);
                                  PostThreadMessage(MainThreadID, WM_SEND_LINE, CurrentID, (LPARAM)(line.c_str()));
                              }
                              file.close();
                              PostThreadMessage(MainThreadID, WM_EOF, CurrentID, 0);
                          }
                          break;
                      }
       
                      case WM_QUIT:
                      {
                          fDone=true;
                          break;
                      }
                  }
              }
       
          }
       
          return 0;
      }
       
       
      DWORD WINAPI MainThreadFunc(LPVOID lpParam)
      {
          const int ThreadsCount=3;
       
          HANDLE SlaveThread[ThreadsCount];
          DWORD SlaveThreadID[ThreadsCount];
          MSG msg;
          int fDone=0;
       
          cout<<"Main thread was run."<<endl;
       
          for(int i=0; i<ThreadsCount; i++)
          {
              // Create the main thread
              SlaveThread[i] = CreateThread(
              NULL,                           // default security attributes
              0,                              // use default stack size  
              SlaveThreadFunc,                // thread function name
              (void*)GetCurrentThreadId(),    // argument to thread function (CurrentThreadId)
              0,                              // use default creation flags
              &SlaveThreadID[i]);             // returns the thread identifier
       
              if (SlaveThread[i] == NULL)
                  ExitProcess(3);
              else
                  cout<<"Slave thread " << SlaveThreadID[i] << " was run."<<endl;
          }
       
          Sleep(100);
       
          PostThreadMessage(SlaveThreadID[0], WM_READ_FILE, 0, (LPARAM)"file0.txt");
          PostThreadMessage(SlaveThreadID[1], WM_READ_FILE, 0, (LPARAM)"file1.txt");
          PostThreadMessage(SlaveThreadID[2], WM_READ_FILE, 0, (LPARAM)"file2.txt");
          
          while (fDone < ThreadsCount) // lengthy operation
          {
              while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
              {
                  switch(msg.message)
                  {  
                      case WM_SEND_LINE:
                      {
                          cout << "Thread " << DWORD(msg.wParam) << ": " << (char*)msg.lParam << endl;
                          break;
                      }
                      case WM_EOF:
                      {
                          PostThreadMessage(DWORD(msg.wParam), WM_QUIT, 0, 0);
                          fDone++;
                          break;
                      }
                  }
              }
          }
       
          // Wait until all slave threads have terminated.
          WaitForMultipleObjects(ThreadsCount, SlaveThread, TRUE, INFINITE);
       
          // Close all thread handles and free memory allocations.
          for(int i=0; i<ThreadsCount; i++)
          {
              CloseHandle(SlaveThread[i]);
          }
          
          return 0;
      }
       
       
      void main()
      {
          HANDLE MainThread;
          DWORD MainThreadID;
       
          // Create the main thread
          MainThread = CreateThread(
          NULL,                           // default security attributes
          0,                              // use default stack size  
          MainThreadFunc,                 // thread function name
          (void*)GetCurrentThreadId(),    // argument to thread function (CurrentThreadId)
          0,                              // use default creation flags
          &MainThreadID);                 // returns the thread identifier
       
          // Check the return value for success. If CreateThread fails, terminate execution.
          if (MainThread == NULL)
              ExitProcess(3);
       
          // Wait until main thread has terminated.
          WaitForSingleObject(MainThread, INFINITE);
          // Close main thread handle
          CloseHandle(MainThread);
          
          cout<<"Press any key for exit...";
          _getch();
      }


    Проблема в том, что обмен сообщениями идёт, а строки с текстом от подчинённых потоков "теряются", (char*)msg.lParam - пустой.
    ExpandedWrap disabled
      case WM_SEND_LINE:
      {
          cout<<"Thread "<< DWORD(msg.wParam)<<": "<<(char*)msg.lParam<<endl;
          break;
      }


    Если установить небольшую задержку Sleep(10); в цикле while(getline(file, line)){…}, то часть строк начинает доходить. См. скриншоты... Помогите понять в чём проблема?
    Прикреплённая картинка
    Прикреплённая картинка

    Прикреплённая картинка
    Прикреплённая картинка
      >string line;
      >...
      >PostThreadMessage(MainThreadID, WM_SEND_LINE, CurrentID, (LPARAM)(line.c_str()));

      line - указатель, адрес.
      Послали адрес сообщением, оно встало в очередь.
      За это время прочитана новая строка или несколько, память под line при этом перераспределилась, и по отосланному адресу уже никто не живёт.
      Сообщение наконец пришло в главный поток. Он глядь - а по тому адресу мусор.

      простые варианты решения
      - выделять каждый раз новую строку, а старую пусть освобождает главный поток.
      - создать единую потокобезопасную очередь, в которую потоки складывают строки, а главный ее разгребает
        Цитата MBo @

        Спасибо за подсказку! Думаю проблема решена...
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0,0326 ]   [ 18 queries used ]   [ Generated: 29.03.24, 13:50 GMT ]