Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.232.188.122] |
|
Сообщ.
#1
,
|
|
|
Пишу многопоточную программу для поиска файлов.
Для создания потоков использую _beginthreadex. Но программа запускается и через некоторое время завершается(без ошибок),а должна выводить путь к файлам в консоль. Без создания потоков(при работе в основном потоке программы) всё работает,файлы находятся и выводятся. Подскажите,пожалуйста,в чём ошибка? Компилирую из консоли gcc main.c -o char -static -s -Wall -Wextra -Werror -W #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; } |
Сообщ.
#2
,
|
|
|
Если я правильно отреверсил,что ты хотел написать, то 68-я строка абсолютно лишняя. Она пытается удалить память, которая ни разу не в хипе.
Кроме того, переопределение MAX_PATH ничего тебе не даст. Ограничение на длину буфера в ANSI-функциях WinAPI является фундаментальным. Вроде бы можно это отключить в Win10 где-то в реестре, но подробностей я не знаю. Ограничения на MAX_PATH изначально лишены Unicode-функции WinAPI, только маршрут при этом надо начинать с L"\\?\" |
Сообщ.
#3
,
|
|
|
Цитата Qraizer @ 68-я строка абсолютно лишняя. Спасибо,исправлю. Но всё же,как быть с потоками? Я несколько раз пересматривал на microsoft, просмотрел с десяток примеров на форумах и блогах. Мой код,вроде,по феншую(что касается создания потоков). Но функция не выводит файлы,да и вообще не запускается. При этом (HANDLE)_beginthreadex не возвращает NULL. Как бы потоки созданы. Пробовал в 22 строку просто вписать типо printf("hello\r\n"); И это не вывелось... . |
Сообщ.
#4
,
|
|
|
Цитата Sherman @ Но функция не выводит файлы,да и вообще не запускается. Убери мьютекс, совсем. В этой задаче он не нужен. |
Сообщ.
#5
,
|
|
|
Цитата Олег М @ Убери мьютекс, совсем. В этой задаче он не нужен. В этом примере,согласен. Оставил его по причине того,что на месте printf будут создаваться потоки функции копирования файла,а в ней будет изменяться глобальная переменная типа int(счётчик созданных потоков),после чего,разлочиваться. |
Сообщ.
#6
,
|
|
|
Цитата Sherman @ В этом примере,согласен. Оставил его по причине того,что на месте printf будут создаваться потоки функции копирования файла,а в ней будет изменяться глобальная переменная Там он тоже не нужен. Ты используешь его для доступа к глобальным переменным, можно обойтись без них - передавай параметром в функцию потока не char *, а указатель на структуру. а вообще, начни с простого 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; } |
Сообщ.
#7
,
|
|
|
В конце функции потока SearchFiles2 была функция _endthreadex(0); заменил на return 0; всё заработало... .
Спасибо за помощь,тему не закрываю,попробую из этого потока создавать потоки на каждый файл. Результаты доложу |
Сообщ.
#8
,
|
|
|
Цитата Sherman @ В конце функции потока SearchFiles2 была функция _endthreadex(0); заменил на return 0; всё заработало... . Вообще, вызов этой функций в конце потока вроде никак не должен влиять (хотя вызывать её не нужно). Т.е. ты опять показал какой-то урезанный код? |
Сообщ.
#9
,
|
|
|
Есть вопрос.
Я создаю поток и пишу его в HANDLE И таких 10,например. Когда их становится 10,жду завершения и обнуляю счётчик Нужно ли мне закрывать HANDLE перед созданием новых потоков или просто они перепишутся? 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); } |
Сообщ.
#10
,
|
|
|
Цитата Sherman @ Нужно ли мне закрывать HANDLE перед созданием новых потоков или просто они перепишутся? Конечно нужно. Для каждого вызова _beginthreadex должен вызыватся ::CloseHandle, иначе будет нефиговая утечка ресурсов. |
Сообщ.
#11
,
|
|
|
Цитата Олег М @ Т.е. ты опять показал какой-то урезанный код? Нет,сам не понял как получилось.Сотни раз пишу,переписываю и вышло так,что здесь return NULL,а у меня это. А код весь,что есть на данный момент. Приступаю к написанию потоковой функции работы с найденными файлами. Добавлено Цитата Олег М @ Конечно нужно. Для каждого вызова _beginthreadex должен вызыватся ::CloseHandle, иначе будет нефиговая утечка ресурсов. Понял,спасибо. Добавлено Цитата Олег М @ Вообще, вызов этой функций в конце потока вроде никак не должен влиять (хотя вызывать её не нужно). "Поток, который создается с помощью _beginthreadex завершается путем вызова _endthreadex." Написано на сайте microsoft, вот я и влепил. |
Сообщ.
#12
,
|
|
|
Спустя пару минут прогона 24 потоков функции,в которой записанные строки выводятся в консоль,выдало ошибку
"Код исключения: c0000024" 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; } |
Сообщ.
#13
,
|
|
|
Имя события проблемы: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 |
Сообщ.
#14
,
|
|
|
Цитата Sherman @ Спустя пару минут прогона 24 потоков функции,в которой записанные строки выводятся в консоль,выдало ошибку "Код исключения: c0000024" Ты уверен, что у тебя все пути помещаются в MAX_PATH? Поставь проверку |
Сообщ.
#15
,
|
|
|
Цитата Олег М @ Ты уверен, что у тебя все пути помещаются в MAX_PATH? Поставь проверку Нет,не уверен.А если нет,могу ли я вписать 1024,например? Не будет ли каракулей и т.п.? Или нужно malloc юзать? А как грамотно сделать проверку,strlen()? |
Сообщ.
#16
,
|
|
|
Цитата Sherman @ как грамотно сделать проверку,strlen()? Сделай malloc(strlen(...) + 1) |
Сообщ.
#17
,
|
|
|
Цитата Олег М @ Сделай malloc(strlen(...) + 1) Сделал так: 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 раза тем же методом. Ошибка не появилась. Спасибо за совет) |
Сообщ.
#18
,
|
|
|
В общем,основной поток не ждёт завершения "дочерних" потоков.
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 сек. Заметил,что в каждом цикле на разных файлах заканчивается вывод. Иногда попадает на последний на диске(выводит согласно алфавиту),но часто не доходит до него. |
Сообщ.
#19
,
|
|
|
Цитата Sherman @ Пишу многопоточную программу для поиска файлов. Для создания потоков использую _beginthreadex. ... Подскажите,пожалуйста,в чём ошибка? Компилирую из консоли gcc main.c -o char -static -s -Wall -Wextra -Werror -W Можно почитать известную книгу Рихтера, глава 6. (стр 130) _beginthreadex - эта функция не является функцией Виндус. Это некая обёртка вокруг "CreateThread" для ликвидации неких внутренних проблем потоко-безопасных библиотек Микрософта ! А будет ли полезно и чем закончится её применение для библиотек других производителей других компиляторов вообще не известно. |
Сообщ.
#20
,
|
|
|
Цитата ЫукпШ @ _beginthreadex - эта функция не является функцией Виндус. Это некая обёртка вокруг "CreateThread" для ликвидации неких внутренних проблем потоко-безопасных библиотек Микрософта ! Но на том же сайте упамянутого Майкрософта написано,мол "Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции _beginthreadex и _endthreadex для управления потоками..." Или это не мой случай? |
Сообщ.
#21
,
|
|
|
Цитата Sherman @ На диске около 200 txt файлов. Поиск происходит в 3 цикла с перерывом 5 сек. Заметил,что в каждом цикле на разных файлах заканчивается вывод. Иногда попадает на последний на диске(выводит согласно алфавиту),но часто не доходит до него. Здесь у тебя вроде всё правильно, ошибка где-то в другом месте. А вообще - это очень хреновая идея делать по потоку на файл. Обычно такие задачи решаются при помощи пула потоков. Добавлено Цитата Sherman @ Но на том же сайте упамянутого Майкрософта написано,мол "Поток в исполняемом файле, который вызывает библиотеку времени выполнения C (CRT), должен использовать функции _beginthreadex и _endthreadex для управления потоками..." Или это не мой случай? Твой. Только _endthreadex не нужно вызывать, он сам вызовется. |
Сообщ.
#22
,
|
|
|
Цитата Олег М @ Обычно такие задачи решаются при помощи пула потоков. Есть какая-нибудь ссылка на пример или что-нибудь,где подсмотреть,как это делается? |
Сообщ.
#23
,
|
|
|
Цитата Sherman @ Есть какая-нибудь ссылка на пример или что-нибудь,где подсмотреть,как это делается? У меня нет, я не занимался такими задачами. Думаю здесь оптимальным будет создать 3 потока: 1-й Ищет файлы, складывает их имена в очередь 2-й Берёт из очереди имя файла, начитывает его небольшими, ~4К, блоками и складывает их в другую очередь (желательно с контролем размера, т.к. чтение быстрее записи) 3-й Берёт блоки из очереди и сохраняет их в соответствующие файлы И, лучше решать эту задачу на с++. Зачем тебе именно Си? |
Сообщ.
#24
,
|
|
|
Цитата Олег М @ Зачем тебе именно Си? Так уж пал мой взгляд на изучение программирования на Си.Вот и пытаюсь реализовать задумку на этом языке. Цитата Олег М @ Ищет файлы, складывает их имена в очередь char **files = (char**)malloc(3e+7 * sizeof(char)); Это подойдёт для очереди? Если да,то как определить размер (3e+7 * sizeof(char)) ,если я не знаю,сколько я получу строк? |
Сообщ.
#25
,
|
|
|
Цитата Sherman @ Это подойдёт для очереди? Нет не подойдёт. Здесь подойдёт только FIFO-стек, который реализуется либо как список, либо как циклический массив. Цитата Sherman @ Так уж пал мой взгляд на изучение программирования на Си.Вот и пытаюсь реализовать задумку на этом языке. Ну, с одной стороны полезно, для общего развития. Хотя смысла мало, а упустишь в современном программировании много. |
Сообщ.
#26
,
|
|
|
Цитата Олег М @ Ну, с одной стороны полезно, для общего развития. Хотя смысла мало, а упустишь в современном программировании много. Возможно,но пока это на уровне любимого хобби. Цитата Олег М @ Здесь подойдёт только FIFO-стек О,новые слова..... Буду искать)) |
Сообщ.
#27
,
|
|
|
Цитата Sherman @ Возможно,но пока это на уровне любимого хобби. Я бы не стал тратить время, ты мало чему научишься. Лучше всё делать на с++. Цитата Sherman @ О,новые слова..... Буду искать)) Если хочешь научиться базовым алгоритмам (по-моему, у тебя именно с ними проблема), просто не используй стандартную библиотеку, реализуй все эти списки-массивы сам. |
Сообщ.
#28
,
|
|
|
Цитата Олег М @ реализуй все эти списки-массивы сам Спасибо за совет,попробую. |