На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Не работает функция в потоке _beginthreadex , Не работает функция в потоке _beginthreadex
    Пишу многопоточную программу для поиска файлов.
    Для создания потоков использую _beginthreadex.
    Но программа запускается и через некоторое время завершается(без ошибок),а должна выводить путь к файлам в консоль.
    Без создания потоков(при работе в основном потоке программы) всё работает,файлы находятся и выводятся.
    Подскажите,пожалуйста,в чём ошибка?
    Компилирую из консоли gcc main.c -o char -static -s -Wall -Wextra -Werror -W
    ExpandedWrap disabled
      #include <stdio.h>
      #include <stdlib.h>
      #include <windows.h>
      #include <sys/stat.h>
      #include <assert.h>
      #include <signal.h>
      #include <unistd.h>
       
      #ifndef MAX_PATH
      #define MAX_PATH 1024
      #endif
       
      HANDLE hMutex;
       
      int find_file = 0, drive = 0;
       
      unsigned __stdcall SearchFiles2(void* lpszFile)
      {
          CONST char *lpszFileName = (CONST char *)lpszFile;
          char path[MAX_PATH] = { 0 };
          char temp[MAX_PATH] = { 0 };
       
          strcpy(path, lpszFileName);
          strcat(path, "*.*");
       
          HANDLE hand;
          WIN32_FIND_DATA data_file;
          hand = FindFirstFile(path, &data_file);
       
          if (hand != INVALID_HANDLE_VALUE)
          {
              do
              {
                  if (!strncmp(data_file.cFileName, ".", 1) || !strncmp(data_file.cFileName, "..", 2))
                  {
                      continue;
                  }
                  if (data_file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                  {
                      strcpy(path, lpszFileName);
                      strcat(path, data_file.cFileName);
                      strcat(path, "\\");
       
                      strcpy(temp, path);
                      strlwr(temp);
                      if (!lstrcmp(temp, "c:\\windows\\") == 0)
                      {
                          SearchFiles(path);
                      }
                  }
                  else
                  {
                          WaitForSingleObject(hMutex, INFINITE);
       
                          char *file = (char*)malloc(strlen(lpszFileName) + strlen(data_file.cFileName) + 64);
                          assert(file);
       
                          strcpy(file, lpszFileName);
                          strcat(file, data_file.cFileName);
       
                          printf("%s\r\n", file);
       
                          ReleaseMutex(hMutex);
                  }
              } while (FindNextFile(hand, &data_file) != 0);
          }
          FindClose(hand);
          free(lpszFile);
       
          return NULL;
      }
       
      int main(void)
      {
          char buf[BUF_PATH] = { 0 };
          char drives[32][10] = { 0 };
          GetLogicalDriveStringsA(sizeof(buf), buf);
          for (char *s = buf; *s; s += strlen(s) + 1)
          {
              strcpy(drives[drive], s);
              drive++;
          }
       
          HANDLE hThreads[drive];
          hMutex = CreateMutex(NULL, FALSE, NULL);
       
          for(int i = 0; i < drive; i++) {
              hThreads[i] = (HANDLE)_beginthreadex(NULL, 0, &SearchFiles2, (void *)drives[i], 0, NULL);
              if(NULL == hThreads[i])
                  printf("Failed to create thread.\r\n");
          }
       
          WaitForMultipleObjects(drive, hThreads, TRUE, INFINITE);
       
          for(int i = 0; i < drive; i++)
              CloseHandle(hThreads[i]);
       
          CloseHandle(hMutex);
          
          return 0;
      }
      Если я правильно отреверсил,что ты хотел написать, то 68-я строка абсолютно лишняя. Она пытается удалить память, которая ни разу не в хипе.
      Кроме того, переопределение MAX_PATH ничего тебе не даст. Ограничение на длину буфера в ANSI-функциях WinAPI является фундаментальным. Вроде бы можно это отключить в Win10 где-то в реестре, но подробностей я не знаю. Ограничения на MAX_PATH изначально лишены Unicode-функции WinAPI, только маршрут при этом надо начинать с L"\\?\"
        Цитата Qraizer @
        68-я строка абсолютно лишняя.

        Спасибо,исправлю.
        Но всё же,как быть с потоками?
        Я несколько раз пересматривал на microsoft, просмотрел с десяток примеров на форумах и блогах.
        Мой код,вроде,по феншую(что касается создания потоков).
        Но функция не выводит файлы,да и вообще не запускается.
        При этом (HANDLE)_beginthreadex не возвращает NULL.
        Как бы потоки созданы.
        Пробовал в 22 строку просто вписать типо printf("hello\r\n");
        И это не вывелось... .
          Цитата Sherman @
          Но функция не выводит файлы,да и вообще не запускается.

          Убери мьютекс, совсем. В этой задаче он не нужен.
            Цитата Олег М @
            Убери мьютекс, совсем. В этой задаче он не нужен.

            В этом примере,согласен.
            Оставил его по причине того,что на месте printf будут создаваться потоки функции копирования файла,а в ней будет изменяться глобальная переменная
            типа int(счётчик созданных потоков),после чего,разлочиваться.
            Сообщение отредактировано: Sherman -
              Цитата Sherman @
              В этом примере,согласен.
              Оставил его по причине того,что на месте printf будут создаваться потоки функции копирования файла,а в ней будет изменяться глобальная переменная

              Там он тоже не нужен. Ты используешь его для доступа к глобальным переменным, можно обойтись без них - передавай параметром в функцию потока не char *, а указатель на структуру.

              а вообще, начни с простого
              ExpandedWrap disabled
                unsigned __stdcall SearchFiles2(void* lpszFile)
                {
                    printf("start thread\n");
                ..........................
                    if (hand != INVALID_HANDLE_VALUE)
                    {
                        do
                        {
                          printf("%s\n", data_file.cFileName);
                 
                        } while (FindNextFile(hand, &data_file) != 0);
                    }
                    FindClose(hand);
                    free(lpszFile);
                 
                    printf("stop thread\n");
                    return NULL;
                }
                В конце функции потока SearchFiles2 была функция _endthreadex(0); заменил на return 0; всё заработало... .
                Спасибо за помощь,тему не закрываю,попробую из этого потока создавать потоки на каждый файл.
                Результаты доложу :D
                  Цитата Sherman @
                  В конце функции потока SearchFiles2 была функция _endthreadex(0); заменил на return 0; всё заработало... .


                  Вообще, вызов этой функций в конце потока вроде никак не должен влиять (хотя вызывать её не нужно).
                  Т.е. ты опять показал какой-то урезанный код?
                    Есть вопрос.
                    Я создаю поток и пишу его в HANDLE

                    И таких 10,например.
                    Когда их становится 10,жду завершения и обнуляю счётчик

                    Нужно ли мне закрывать HANDLE перед созданием новых потоков или просто они перепишутся?
                    ExpandedWrap disabled
                                
                      if( memory(1) < 86 &&   // memory(1) возвращает целое число,равное % загрузки памяти
                          find_file < THREADS_NUMBER )  // THREADS_NUMBER 10 потоков, find_file плюсуется в функции потока
                      {
                         hFileThreads[find_file] = (HANDLE)_beginthreadex(NULL, 0, &Thread, (void *)file, 0, NULL);
                      }
                      else
                      {
                         WaitForMultipleObjects(find_file, hFileThreads, TRUE, INFINITE);
                                              
                         find_file = 0;
                                          
                         hFileThreads[find_file] = (HANDLE)_beginthreadex(NULL, 0, &Thread, (void *)file, 0, NULL);
                      }
                      Цитата Sherman @
                      Нужно ли мне закрывать HANDLE перед созданием новых потоков или просто они перепишутся?

                      Конечно нужно. Для каждого вызова _beginthreadex должен вызыватся ::CloseHandle, иначе будет нефиговая утечка ресурсов.
                        Цитата Олег М @
                        Т.е. ты опять показал какой-то урезанный код?

                        Нет,сам не понял как получилось.Сотни раз пишу,переписываю и вышло так,что здесь return NULL,а у меня это.
                        А код весь,что есть на данный момент.
                        Приступаю к написанию потоковой функции работы с найденными файлами.

                        Добавлено
                        Цитата Олег М @
                        Конечно нужно. Для каждого вызова _beginthreadex должен вызыватся ::CloseHandle, иначе будет нефиговая утечка ресурсов.

                        Понял,спасибо.

                        Добавлено
                        Цитата Олег М @
                        Вообще, вызов этой функций в конце потока вроде никак не должен влиять (хотя вызывать её не нужно).

                        "Поток, который создается с помощью _beginthreadex завершается путем вызова _endthreadex."
                        Написано на сайте microsoft, вот я и влепил.
                        Сообщение отредактировано: Sherman -
                          Спустя пару минут прогона 24 потоков функции,в которой записанные строки выводятся в консоль,выдало ошибку
                          "Код исключения: c0000024"
                          ExpandedWrap disabled
                            unsigned __stdcall Thread(void * ffile)
                            {
                                char fille[MAX_PATH] = { 0 };
                                strcpy(fille, (CONST char *)ffile);
                                free(ffile);
                             
                                find_file++;
                             
                                ReleaseMutex(hMutex);
                              
                                printf("%s\r\n", fille);
                                Sleep(find_file * 5L); //небольшая задержка,которая увеличивается,как бы имитация какой-то работы с файлами разного объёма.
                             
                                return 0;
                            }
                          Сообщение отредактировано: Sherman -
                            ExpandedWrap disabled
                                Имя события проблемы:APPCRASH
                                Имя приложения:char.exe
                                Версия приложения:0.0.0.0
                                Отметка времени приложения:5cd0387a
                                Имя модуля с ошибкой:ntdll.dll
                                Версия модуля с ошибкой:6.3.9600.18821
                                Отметка времени модуля с ошибкой:59ba8666
                                Код исключения:c0000024
                                Смещение исключения:0007d313
                                Версия ОС:6.3.9600.2.0.0.768.100
                                Код языка:1049
                              Цитата Sherman @
                              Спустя пару минут прогона 24 потоков функции,в которой записанные строки выводятся в консоль,выдало ошибку
                              "Код исключения: c0000024"


                              Ты уверен, что у тебя все пути помещаются в MAX_PATH? Поставь проверку
                                Цитата Олег М @
                                Ты уверен, что у тебя все пути помещаются в MAX_PATH? Поставь проверку

                                Нет,не уверен.А если нет,могу ли я вписать 1024,например?
                                Не будет ли каракулей и т.п.?
                                Или нужно malloc юзать?
                                А как грамотно сделать проверку,strlen()?
                                  Цитата Sherman @
                                  как грамотно сделать проверку,strlen()?

                                  Сделай malloc(strlen(...) + 1)
                                    Цитата Олег М @
                                    Сделай malloc(strlen(...) + 1)

                                    Сделал так:
                                    ExpandedWrap disabled
                                      unsigned __stdcall SearchFiles2(void* lpszFile)
                                      {
                                          char *lpszFileName = (char*)malloc(2048 * sizeof(char));
                                          strcpy(lpszFileName, (char *)lpszFile);
                                          char *path = (char*)malloc(strlen(lpszFileName) * sizeof(char) + 255);
                                          char *temp = (char*)malloc(strlen(lpszFileName) * sizeof(char) + 255);
                                       
                                          strcpy(path, lpszFileName);
                                          strcat(path, "*.*");
                                       
                                      /*...........................................*/
                                       
                                          FindClose(hand);
                                       
                                          free(lpszFileName);
                                          free(path);
                                          free(temp);
                                       
                                          return 0;
                                      }

                                    Всё остальное без изменения.
                                    Прогнал весь системный диск(примерно 310т. файлов) 3 раза тем же методом.
                                    Ошибка не появилась.
                                    Спасибо за совет)
                                    Сообщение отредактировано: Sherman -
                                      В общем,основной поток не ждёт завершения "дочерних" потоков.
                                      ExpandedWrap disabled
                                            WaitForMultipleObjects(drive, hThreads, TRUE, INFINITE);
                                            WaitForMultipleObjects(find_file, hFileThreads, TRUE, INFINITE);
                                         
                                            for(int i = 0; i < find_file; i++)
                                                CloseHandle(hFileThreads[i]);
                                         
                                            for(int i = 0; i < drive; i++)
                                                CloseHandle(hThreads[i]);

                                      использую это в основном потоке,где
                                      hThreads - потоки функции поиска файлов и записи их нахождения в char *file;(сколько дисков,столько и потоков,но пока проверяю на 1 диске)
                                      hFileThreads - потоки функции вывода вывода char *file в консоль.(стоит 100)

                                      На диске около 200 txt файлов.
                                      Поиск происходит в 3 цикла с перерывом 5 сек.
                                      Заметил,что в каждом цикле на разных файлах заканчивается вывод.
                                      Иногда попадает на последний на диске(выводит согласно алфавиту),но часто не доходит до него.
                                        Цитата Sherman @
                                        Пишу многопоточную программу для поиска файлов.
                                        Для создания потоков использую _beginthreadex.
                                        ...
                                        Подскажите,пожалуйста,в чём ошибка?
                                        Компилирую из консоли gcc main.c -o char -static -s -Wall -Wextra -Werror -W

                                        Можно почитать известную книгу Рихтера, глава 6. (стр 130)
                                        _beginthreadex - эта функция не является функцией Виндус.
                                        Это некая обёртка вокруг "CreateThread" для ликвидации неких
                                        внутренних проблем потоко-безопасных библиотек Микрософта !
                                        А будет ли полезно и чем закончится её применение для библиотек
                                        других производителей других компиляторов вообще не известно.
                                        Сообщение отредактировано: ЫукпШ -
                                          Цитата ЫукпШ @
                                          _beginthreadex - эта функция не является функцией Виндус.
                                          Это некая обёртка вокруг "CreateThread" для ликвидации неких
                                          внутренних проблем потоко-безопасных библиотек Микрософта !

                                          Но на том же сайте упамянутого Майкрософта написано,мол
                                          "Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции _beginthreadex и _endthreadex для управления потоками..."
                                          Или это не мой случай?
                                            Цитата Sherman @
                                            На диске около 200 txt файлов.
                                            Поиск происходит в 3 цикла с перерывом 5 сек.
                                            Заметил,что в каждом цикле на разных файлах заканчивается вывод.
                                            Иногда попадает на последний на диске(выводит согласно алфавиту),но часто не доходит до него.


                                            Здесь у тебя вроде всё правильно, ошибка где-то в другом месте.

                                            А вообще - это очень хреновая идея делать по потоку на файл. Обычно такие задачи решаются при помощи пула потоков.

                                            Добавлено
                                            Цитата Sherman @
                                            Но на том же сайте упамянутого Майкрософта написано,мол
                                            "Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции _beginthreadex и _endthreadex для управления потоками..."
                                            Или это не мой случай?


                                            Твой. Только _endthreadex не нужно вызывать, он сам вызовется.
                                              Цитата Олег М @
                                              Обычно такие задачи решаются при помощи пула потоков.

                                              Есть какая-нибудь ссылка на пример или что-нибудь,где подсмотреть,как это делается?
                                                Цитата Sherman @
                                                Есть какая-нибудь ссылка на пример или что-нибудь,где подсмотреть,как это делается?

                                                У меня нет, я не занимался такими задачами.

                                                Думаю здесь оптимальным будет создать 3 потока:
                                                1-й Ищет файлы, складывает их имена в очередь
                                                2-й Берёт из очереди имя файла, начитывает его небольшими, ~4К, блоками и складывает их в другую очередь (желательно с контролем размера, т.к. чтение быстрее записи)
                                                3-й Берёт блоки из очереди и сохраняет их в соответствующие файлы

                                                И, лучше решать эту задачу на с++. Зачем тебе именно Си?
                                                  Цитата Олег М @
                                                  Зачем тебе именно Си?

                                                  Так уж пал мой взгляд на изучение программирования на Си.Вот и пытаюсь реализовать задумку на этом языке.
                                                  Цитата Олег М @
                                                  Ищет файлы, складывает их имена в очередь

                                                  char **files = (char**)malloc(3e+7 * sizeof(char));
                                                  Это подойдёт для очереди?
                                                  Если да,то как определить размер (3e+7 * sizeof(char)) ,если я не знаю,сколько я получу строк?
                                                    Цитата Sherman @
                                                    Это подойдёт для очереди?

                                                    Нет не подойдёт. Здесь подойдёт только FIFO-стек, который реализуется либо как список, либо как циклический массив.

                                                    Цитата Sherman @
                                                    Так уж пал мой взгляд на изучение программирования на Си.Вот и пытаюсь реализовать задумку на этом языке.

                                                    Ну, с одной стороны полезно, для общего развития. Хотя смысла мало, а упустишь в современном программировании много.
                                                      Цитата Олег М @
                                                      Ну, с одной стороны полезно, для общего развития. Хотя смысла мало, а упустишь в современном программировании много.

                                                      Возможно,но пока это на уровне любимого хобби.

                                                      Цитата Олег М @
                                                      Здесь подойдёт только FIFO-стек

                                                      О,новые слова.....
                                                      Буду искать))
                                                        Цитата Sherman @
                                                        Возможно,но пока это на уровне любимого хобби.

                                                        Я бы не стал тратить время, ты мало чему научишься. Лучше всё делать на с++.

                                                        Цитата Sherman @
                                                        О,новые слова.....
                                                        Буду искать))


                                                        Если хочешь научиться базовым алгоритмам (по-моему, у тебя именно с ними проблема), просто не используй стандартную библиотеку, реализуй все эти списки-массивы сам.
                                                          Цитата Олег М @
                                                          реализуй все эти списки-массивы сам

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


                                                          Рейтинг@Mail.ru
                                                          [ Script execution time: 0,0909 ]   [ 17 queries used ]   [ Generated: 19.03.24, 02:42 GMT ]