Я построил этот многочисленный поиск в файле с использованием событий и критических разделов. Это сделано для ускорения приложения. У меня также есть последний отдельный поток (SearchThread), который соответствует строке имени файла в обнаруженных путях файла. Я установил критические разделы для предотвращения условий гонки данных и событий для уведомления о спальных потоках для выполнения необходимых задач при пробуждении. Но это не сработает, как и ожидалось. Один, расположенный по адресу d: \ search \ my_search_item.txt (что он не поднимает), а другой, расположенный по адресу d: \ search \ test \ my_search_item.txt (что он поднимает дважды).
Любые идеи о том, как я могу исправить это?
#include
#include
#include // For malloc, realloc, free
#include
#include // For wcslen and wcscpy
HANDLE hNewFileItemEvent;
HANDLE hNewSearchItemEvent;
HANDLE hNoMoreWorkEvent;
WCHAR* filePath;
WIN32_FIND_DATAW fd;
WCHAR subPath[MAX_PATH];
const WCHAR* rootPath = L"D:\\search";
CRITICAL_SECTION g_queueCS;
typedef struct {
WCHAR** data; // Pointer to an array of string pointers
int size; // Current number of strings in the array
int capacity; // Allocated capacity of the array
} StringDynamicArray;
StringDynamicArray myFolders;
StringDynamicArray myFiles;
void initStringDynamicArray(StringDynamicArray* arr, int initialCapacity) {
arr->data = (WCHAR**)malloc(sizeof(WCHAR*) * initialCapacity);
if (arr->data == NULL) {
perror("Failed to allocate initial memory for string array");
exit(EXIT_FAILURE);
}
arr->size = 0;
arr->capacity = initialCapacity;
}
void pushString(StringDynamicArray* arr, const WCHAR* str) {
if (arr->size == arr->capacity) {
arr->capacity *= 2;
arr->data = (WCHAR**)realloc(arr->data, sizeof(WCHAR*) * arr->capacity);
if (arr->data == NULL) {
perror("Failed to reallocate memory for string array");
exit(EXIT_FAILURE);
}
}
size_t strLen = wcslen(str);
arr->data[arr->size] = (WCHAR*)malloc((strLen + 1) * sizeof(wchar_t)); // +1 for null terminator
if (arr->data[arr->size] == NULL) {
perror("Failed to allocate memory for string");
exit(EXIT_FAILURE);
}
// Use wcscpy_s with the correct buffer size (strLen + 1)
errno_t err = wcscpy_s(arr->data[arr->size], strLen + 1, str);
if (err == 0) {
wprintf(L"Successfully copied: %ls\n", arr->data[arr->size]);
arr->size++;
}
else {
wprintf(L"Error copying string. Error code: %d\n", err);
}
}
WCHAR* popString(StringDynamicArray* arr) {
if (arr->size == 0) {
fprintf(stderr, "Error: Cannot pop from an empty array.\n");
return NULL;
}
arr->size--;
WCHAR* poppedStr = arr->data[arr->size];
return poppedStr; // Caller is responsible for freeing this memory
}
void freeStringDynamicArray(StringDynamicArray* arr) {
for (int i = 0; i < arr->size; i++) {
free(arr->data[i]); // Free individual strings
}
free(arr->data); // Free the array of pointers
arr->data = NULL;
arr->size = 0;
arr->capacity = 0;
}
void searchDirectories(const WCHAR* path) {
WIN32_FIND_DATAW findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
WCHAR searchPath[MAX_PATH];
WCHAR subPath[MAX_PATH];
// Construct the search pattern (e.g., "D:\\search\\*")
swprintf_s(searchPath, MAX_PATH, L"%s\\*", path);
// Start the search with FindFirstFileW
hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
wprintf(L"Error opening directory %s: %d\n", path, GetLastError());
return;
}
// Iterate through all files and directories
do {
// Skip the current (".") and parent ("..") directories
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) {
continue;
}
// Construct the full path of the current file or directory
swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path
wprintf(L"%s\n", subPath);
// If it's a directory, recursively search it
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
pushString(&myFolders, (LPCWSTR)subPath);
searchDirectories(subPath);
}
} while (FindNextFileW(hFind, &findData) != 0);
// Check if the loop ended due to an error
DWORD error = GetLastError();
if (error != ERROR_NO_MORE_FILES) {
wprintf(L"Error during directory search: %d\n", error);
}
// Close the search handle
FindClose(hFind);
}
//IN each directory provided as an argument search for all files in it
void searchFiles(const WCHAR* path) {
WIN32_FIND_DATAW findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
WCHAR searchPath[MAX_PATH];
WCHAR subPath[MAX_PATH];
swprintf_s(searchPath, MAX_PATH, L"%s\\*", path);
// Start the search with FindFirstFileW
hFind = FindFirstFileW(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) {
wprintf(L"Error opening directory %s: %d\n", path, GetLastError());
return;
}
// Iterate through all files and directories
do {
// Skip the current (".") and parent ("..") directories
if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) {
continue;
}
// Construct the full path of the current file or directory
swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path
wprintf(L"%s\n", subPath);
// If it's NOT a directory, write it to the myFiles Struct
if (findData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) {
::EnterCriticalSection(&g_queueCS);
printf("Size: %d\n", myFiles.size);
pushString(&myFiles, (LPCWSTR)subPath);
::LeaveCriticalSection(&g_queueCS);
::SetEvent(hNewSearchItemEvent);
}
} while (FindNextFileW(hFind, &findData) != 0);
// Check if the loop ended due to an error
DWORD error = GetLastError();
if (error != ERROR_NO_MORE_FILES) {
wprintf(L"Error during directory search: %d\n", error);
}
// Close the search handle
FindClose(hFind);
}
BOOL FileMatchesSearch(WCHAR fullPath[], WCHAR targetString[]) {
size_t fullPathLen = wcslen(fullPath);
size_t targetStringLen = wcslen(targetString);
// Check if the full path is long enough to contain the target string
if (fullPathLen >= targetStringLen) {
// Get a pointer to the potential start of the target string in fullPath
WCHAR* endOfPath = fullPath + (fullPathLen - targetStringLen);
// Compare the substring with the target string
if (wcscmp(endOfPath, targetString) == 0) {
//printf("'%ws' exists at the end of the path.\n", targetString);
printf("File path found: %ws\n", fullPath);
return TRUE;
}
else {
printf("'%ws' does NOT exist at the end of the path.\n", targetString);
return FALSE;
}
}
else {
printf("The path is too short to contain '%ws'.\n", targetString);
return FALSE;
}
}
DWORD WINAPI FolderThread(PVOID) {
searchDirectories(rootPath);
::SetEvent(hNewFileItemEvent);
return 42;
}
DWORD WINAPI FileThread(LPVOID lpParam) {
const WCHAR* folderPath = (WCHAR*)lpParam;
wprintf(L"Processing string: %s\n", folderPath);
while (true) {
HANDLE waitHandles[2] = { hNewFileItemEvent, hNoMoreWorkEvent };
DWORD waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
if (waitResult == WAIT_OBJECT_0 + 1) { // hNoMoreWorkEvent is signaled
return 0; // Exit the thread
}
else {
break;
}
}
searchFiles(folderPath);
return 42;
}
DWORD WINAPI SearchThread(PVOID) {
while (true) {
HANDLE waitHandles[2] = { hNewSearchItemEvent, hNoMoreWorkEvent };
DWORD waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);
if (waitResult == WAIT_OBJECT_0 + 1) { // hNoMoreWorkEvent is signaled
break; // Exit the thread
}
// Else, hNewItemEvent was signaled. Grab work.
//Sleep(10000);
::EnterCriticalSection(&g_queueCS);
if (myFiles.size != 0) {
filePath = popString(&myFiles);
// If we just took the last item, reset the event
}
else if (myFiles.size == 0) {
::ResetEvent(hNewSearchItemEvent);
}
::LeaveCriticalSection(&g_queueCS);
WCHAR searchPattern[] = L"My_search_item.txt";
// Allocate a WCHAR array on the stack, including space for the null terminator
const int MAX_LENGTH = 256; // Or a suitable maximum length
WCHAR destinationArray[MAX_LENGTH];
// Copy the string
wcscpy_s(destinationArray, MAX_LENGTH, filePath);
if (FileMatchesSearch(destinationArray, searchPattern)) {
printf("File Found...!!!\n");
}
}
return 0;
}
int main()
{
::InitializeCriticalSection(&g_queueCS);
initStringDynamicArray(&myFolders, 5);
initStringDynamicArray(&myFiles, 5);
// Create a manual-reset event in a non-signaled state
hNewFileItemEvent = ::CreateEvent(
NULL, // Default security attributes
TRUE, // Manual-reset event
FALSE, // Initial state is non-signaled
L"NewItemEvent" // Name of the event (optional)
);
// Create a manual-reset event in a non-signaled state
hNewSearchItemEvent = ::CreateEvent(
NULL, // Default security attributes
TRUE, // Manual-reset event
FALSE, // Initial state is non-signaled
L"NewItemEvent" // Name of the event (optional)
);
// Create a manual-reset event in a non-signaled state
hNoMoreWorkEvent = ::CreateEvent(
NULL, // Default security attributes
TRUE, // Manual-reset event
FALSE, // Initial state is non-signaled
L"NewItemEvent" // Name of the event (optional)
);
//************************Folder thread
HANDLE hThreadFolder = ::CreateThread(NULL,0, FolderThread, NULL, 0 ,NULL);
::WaitForSingleObject(hThreadFolder, INFINITE);
// Array to store thread handles
HANDLE* threads = (HANDLE*)malloc(myFolders.size * sizeof(HANDLE));
if (!threads) {
wprintf(L"Failed to allocate memory for thread handles\n");
return 1;
}
//**************MULtiple threads to look for files in each folder discovered (One thread per folder)
// Loop through the data array and create a thread for each index
for (int i = 0; i < myFolders.size; i++) {
threads[i] = CreateThread(
NULL, // Default security attributes
0, // Default stack size
FileThread, // Thread function
myFolders.data[i], // Pass the string at index i
0, // Default creation flags
NULL // No thread ID needed
);
if (threads[i] == NULL) {
wprintf(L"Failed to create thread for index %d\n", i);
// Handle error (e.g., clean up and exit)
}
}
// Wait for all threads to complete
WaitForMultipleObjects(myFolders.size, threads, TRUE, INFINITE);
// ****************************Singe thread to Search for the File by file name
HANDLE hThreadSearch = ::CreateThread(NULL, 0, SearchThread, NULL, 0, NULL);
::WaitForSingleObject(hThreadSearch, INFINITE);
// Clean up thread handles
for (int i = 0; i < myFolders.size; i++) {
if (threads[i]) {
CloseHandle(threads[i]);
}
}
// Clean up allocated memory
for (int i = 0; i < myFolders.size; i++) {
free(myFolders.data[i]); // Free each string
}
free(myFolders.data); // Free the array of pointers
free(threads); // Free thread handles array
::CloseHandle(hThreadFolder);
::CloseHandle(hThreadSearch);
::DeleteCriticalSection(&g_queueCS);
freeStringDynamicArray(&myFolders);
freeStringDynamicArray(&myFiles);
return 0;
}
Я построил этот многочисленный поиск в файле с использованием событий и критических разделов. Это сделано для ускорения приложения. У меня также есть последний отдельный поток (SearchThread), который соответствует строке имени файла в обнаруженных путях файла. Я установил критические разделы для предотвращения условий гонки данных и событий для уведомления о спальных потоках для выполнения необходимых задач при пробуждении. Но это не сработает, как и ожидалось. Один, расположенный по адресу d: \ search \ my_search_item.txt (что он не поднимает), а другой, расположенный по адресу d: \ search \ test \ my_search_item.txt (что он поднимает дважды). Любые идеи о том, как я могу исправить это?[code]#include #include #include // For malloc, realloc, free #include #include // For wcslen and wcscpy
typedef struct { WCHAR** data; // Pointer to an array of string pointers int size; // Current number of strings in the array int capacity; // Allocated capacity of the array } StringDynamicArray;
StringDynamicArray myFolders;
StringDynamicArray myFiles;
void initStringDynamicArray(StringDynamicArray* arr, int initialCapacity) { arr->data = (WCHAR**)malloc(sizeof(WCHAR*) * initialCapacity); if (arr->data == NULL) { perror("Failed to allocate initial memory for string array"); exit(EXIT_FAILURE); } arr->size = 0; arr->capacity = initialCapacity; }
void pushString(StringDynamicArray* arr, const WCHAR* str) { if (arr->size == arr->capacity) { arr->capacity *= 2; arr->data = (WCHAR**)realloc(arr->data, sizeof(WCHAR*) * arr->capacity); if (arr->data == NULL) { perror("Failed to reallocate memory for string array"); exit(EXIT_FAILURE); } }
size_t strLen = wcslen(str); arr->data[arr->size] = (WCHAR*)malloc((strLen + 1) * sizeof(wchar_t)); // +1 for null terminator if (arr->data[arr->size] == NULL) { perror("Failed to allocate memory for string"); exit(EXIT_FAILURE); }
// Start the search with FindFirstFileW hFind = FindFirstFileW(searchPath, &findData); if (hFind == INVALID_HANDLE_VALUE) { wprintf(L"Error opening directory %s: %d\n", path, GetLastError()); return; }
// Iterate through all files and directories do { // Skip the current (".") and parent ("..") directories if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) { continue; }
// Construct the full path of the current file or directory swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path wprintf(L"%s\n", subPath);
// If it's a directory, recursively search it if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { pushString(&myFolders, (LPCWSTR)subPath); searchDirectories(subPath); }
} while (FindNextFileW(hFind, &findData) != 0);
// Check if the loop ended due to an error DWORD error = GetLastError(); if (error != ERROR_NO_MORE_FILES) { wprintf(L"Error during directory search: %d\n", error); }
// Close the search handle FindClose(hFind); }
//IN each directory provided as an argument search for all files in it void searchFiles(const WCHAR* path) { WIN32_FIND_DATAW findData; HANDLE hFind = INVALID_HANDLE_VALUE; WCHAR searchPath[MAX_PATH]; WCHAR subPath[MAX_PATH];
swprintf_s(searchPath, MAX_PATH, L"%s\\*", path);
// Start the search with FindFirstFileW hFind = FindFirstFileW(searchPath, &findData); if (hFind == INVALID_HANDLE_VALUE) { wprintf(L"Error opening directory %s: %d\n", path, GetLastError()); return; }
// Iterate through all files and directories do { // Skip the current (".") and parent ("..") directories if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) { continue; }
// Construct the full path of the current file or directory swprintf_s(subPath, MAX_PATH, L"%s\\%s", path, findData.cFileName);
// Print the full path wprintf(L"%s\n", subPath);
// If it's NOT a directory, write it to the myFiles Struct if (findData.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY) { ::EnterCriticalSection(&g_queueCS); printf("Size: %d\n", myFiles.size); pushString(&myFiles, (LPCWSTR)subPath); ::LeaveCriticalSection(&g_queueCS); ::SetEvent(hNewSearchItemEvent); }
} while (FindNextFileW(hFind, &findData) != 0);
// Check if the loop ended due to an error DWORD error = GetLastError(); if (error != ERROR_NO_MORE_FILES) { wprintf(L"Error during directory search: %d\n", error); }
// Check if the full path is long enough to contain the target string if (fullPathLen >= targetStringLen) { // Get a pointer to the potential start of the target string in fullPath WCHAR* endOfPath = fullPath + (fullPathLen - targetStringLen);
// Compare the substring with the target string if (wcscmp(endOfPath, targetString) == 0) { //printf("'%ws' exists at the end of the path.\n", targetString); printf("File path found: %ws\n", fullPath); return TRUE; } else { printf("'%ws' does NOT exist at the end of the path.\n", targetString); return FALSE; } } else { printf("The path is too short to contain '%ws'.\n", targetString); return FALSE; } }
if (waitResult == WAIT_OBJECT_0 + 1) { // hNoMoreWorkEvent is signaled break; // Exit the thread }
// Else, hNewItemEvent was signaled. Grab work. //Sleep(10000); ::EnterCriticalSection(&g_queueCS);
if (myFiles.size != 0) { filePath = popString(&myFiles);
// If we just took the last item, reset the event
} else if (myFiles.size == 0) { ::ResetEvent(hNewSearchItemEvent); } ::LeaveCriticalSection(&g_queueCS);
WCHAR searchPattern[] = L"My_search_item.txt";
// Allocate a WCHAR array on the stack, including space for the null terminator const int MAX_LENGTH = 256; // Or a suitable maximum length WCHAR destinationArray[MAX_LENGTH];
// Copy the string wcscpy_s(destinationArray, MAX_LENGTH, filePath); if (FileMatchesSearch(destinationArray, searchPattern)) { printf("File Found...!!!\n");
} } return 0; }
int main() { ::InitializeCriticalSection(&g_queueCS); initStringDynamicArray(&myFolders, 5); initStringDynamicArray(&myFiles, 5);
// Create a manual-reset event in a non-signaled state hNewFileItemEvent = ::CreateEvent( NULL, // Default security attributes TRUE, // Manual-reset event FALSE, // Initial state is non-signaled L"NewItemEvent" // Name of the event (optional) );
// Create a manual-reset event in a non-signaled state hNewSearchItemEvent = ::CreateEvent( NULL, // Default security attributes TRUE, // Manual-reset event FALSE, // Initial state is non-signaled L"NewItemEvent" // Name of the event (optional) );
// Create a manual-reset event in a non-signaled state hNoMoreWorkEvent = ::CreateEvent( NULL, // Default security attributes TRUE, // Manual-reset event FALSE, // Initial state is non-signaled L"NewItemEvent" // Name of the event (optional) );
// Array to store thread handles HANDLE* threads = (HANDLE*)malloc(myFolders.size * sizeof(HANDLE)); if (!threads) { wprintf(L"Failed to allocate memory for thread handles\n"); return 1; }
//**************MULtiple threads to look for files in each folder discovered (One thread per folder) // Loop through the data array and create a thread for each index for (int i = 0; i < myFolders.size; i++) { threads[i] = CreateThread( NULL, // Default security attributes 0, // Default stack size FileThread, // Thread function myFolders.data[i], // Pass the string at index i 0, // Default creation flags NULL // No thread ID needed );
if (threads[i] == NULL) { wprintf(L"Failed to create thread for index %d\n", i); // Handle error (e.g., clean up and exit) } }
// Wait for all threads to complete WaitForMultipleObjects(myFolders.size, threads, TRUE, INFINITE);
// ****************************Singe thread to Search for the File by file name HANDLE hThreadSearch = ::CreateThread(NULL, 0, SearchThread, NULL, 0, NULL); ::WaitForSingleObject(hThreadSearch, INFINITE);
// Clean up thread handles for (int i = 0; i < myFolders.size; i++) { if (threads[i]) { CloseHandle(threads[i]); } }
// Clean up allocated memory for (int i = 0; i < myFolders.size; i++) { free(myFolders.data[i]); // Free each string } free(myFolders.data); // Free the array of pointers free(threads); // Free thread handles array ::CloseHandle(hThreadFolder); ::CloseHandle(hThreadSearch);