Каким способом быстрее обработать файл? Использовать потоки, DLL или конс. приложен
Имеется приложение, которое выполняет много функций во время работы с файлами. Файлы где-то 20-25 Мб. Требуется искать в них информацию и перекодировать ее из wchar в обычный char.
Дело в том, что вычисление таких операций тратит много времени. Интересует такой вопрос - может быть стоит как-то вынести такие функции за пределы программы, например, в потоки или написать маленькие консольные подпрограммы, которые будут выполнятся через командную строку и передавать данные основной программе?
Имеется приложение, которое выполняет много функций во время работы с файлами. Файлы где-то 20-25 Мб. Требуется искать в них информацию и перекодировать ее из wchar в обычный char.
Дело в том, что вычисление таких операций тратит много времени. Интересует такой вопрос - может быть стоит как-то вынести такие функции за пределы программы, например, в потоки или написать маленькие консольные подпрограммы, которые будут выполнятся через командную строку и передавать данные основной программе?
примерно такую задачу решил следующим образом:
есть список файлов, делаю
deque <HANDLE> dqThread;
в *.cpp:
цикл
dqThread.push_back(CreateThread( NULL , 0 , CheckFile, (LPVOID)FileName, 0 , NULL ));
цикл
сам процесс:
DWORD WINAPI CheckFile (LPVOID FileName)
{
// обработка файла
}
на форме кнопка "Отмена" в обработчике которой цикл по всем процессам и их завершение
ЗЫ: быстрее вряд ли будет, но с основной программой можно будет работать, пока файлы обрабатываются в фоновом режиме
на форме кнопка "Отмена" в обработчике которой цикл по всем процессам и их завершение
Такое завершение некорректно. Поток не должен завершаться принудительно из вне.
Правильнее проверять в потоках некий объект синхронизации, который устанавливается из основного потока для сигнализации отмены выполнения. Далее основной поток ожидает завершения порожденных.
Правильнее проверять в потоках некий объект синхронизации, который устанавливается из основного потока для сигнализации отмены выполнения. Далее основной поток ожидает завершения порожденных.
в описанном мной случае, поток не создает дочерних потоков, поэтому не критично (в контексте задачи, поставленной автором) синхронизировать потоки.
Хотя для общего случая все же синхронизацию лучше делать.
инициализацию/деинициализацию объектов делать вне потока, а в потоке только обрабатывать объекты (ИМХО взял для себя за некое правило)
Ты передаешь в новый поток имя файла:
{
// обработка файла
}
это значит, что файл будет открыт уже в потоке?
Тогда кто его будет закрывать?
Даже если "инициализацию/деинициализацию объектов делать вне потока", что само по себе странно, то все равно ты не сможешь гарантировать освобождение ресурсов занятых потоком, т.к. тогда придется отказаться от использования в потоках каких-либо библиотек (в т.ч. CRT), а так же WinAPI, которые тоже используют ресурсы.
1. Структурированные по заданному типу данные
2. Во время выполнения операции статус заверения (в %)
3. Возможность отмены в любое время
CreateThread( NULL , 0 , ChangeMyObject, (LPVOID)pParam, 0 , NULL );
//-----------------------
DWORD WINAPI ChangeMyObject (LPVOID pParam)
{
// какие то операции над MyObject
}
// ----------------------
void CheckThread (m_Thread)
{
DWORD dwExitCode;
GetExitCodeThread (m_Thread, &dwExitCode);
if (dwExitCode != STILL_ACTIVE)
delete MyObject;
}
PS: в переменную FileName (из 1-го поста) можно передавать не имя файла а его дескриптор (и переименовать ее в handle_file :))
CreateThread( NULL , 0 , ChangeMyObject, (LPVOID)pParam, 0 , NULL );
//-----------------------
DWORD WINAPI ChangeMyObject (LPVOID pParam)
{
// какие то операции над MyObject
}
// ----------------------
void CheckThread (m_Thread)
{
DWORD dwExitCode;
GetExitCodeThread (m_Thread, &dwExitCode);
if (dwExitCode != STILL_ACTIVE)
delete MyObject;
}
При этом ChangeMyObject, если её прерывание является штатным в программе, не может вызывать никаких функций даже из CRT, WinAPI и т.п. Много ли проку от такой функции?
PS: в переменную FileName (из 1-го поста) можно передавать не имя файла а его дескриптор (и переименовать ее в handle_file :))
Опять же, много ли толку от переданного дескриптора? Читать то из файла нельзя, т.к. это вызов ReadFile из WinAPI.
HANDLE hMapFile = NULL;
LPVOID pMemory = NULL;
int FileSize;
__int64 CheckSumm = -1;
hFileRead = CreateFile(FileName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFileRead != NULL)
{
hMapFile = CreateFileMapping(hFileRead, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapFile)
{
pMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
FileSize = GetFileSize(hFileRead, 0);
for (int a = 0; a < FileSize; a++)
{
//Делаю необходимое
}
UnmapViewOfFile(pMemory);
}
CloseHandle(hMapFile);
}
CloseHandle(hFileRead);
И лучше всего делать все это в потоке, да?
А сколько можно создать потоков? Как это зависит от типа процессоров и их количества? На что ориентироваться, создавая потоки и сколько их должно быть?
Опять же, много ли толку от переданного дескриптора? Читать то из файла нельзя, т.к. это вызов ReadFile из WinAPI.
вот такой код работает на ура:
{
CreateThread( NULL , 0 , ChangeForm2, (LPVOID)this, 0 , NULL );
}
//---------------------------------------------------------------------------
DWORD WINAPI ChangeForm2 (LPVOID pForm)
{
TForm2 *fm = (TForm2*) pForm;
for (int i=0; i<100; i++)
{
fm->ProgressBar1->Position++;
Sleep(50);
FindWindow("TForm1", "Form1");
}
return 0;
}
и WinAPI вызывается, и объект можно использовать
{
CreateThread( NULL , 0 , ChangeForm2, (LPVOID)this, 0 , NULL );
}
//---------------------------------------------------------------------------
DWORD WINAPI ChangeForm2 (LPVOID pForm)
{
TForm2 *fm = (TForm2*) pForm;
for (int i=0; i<100; i++)
{
fm->ProgressBar1->Position++;
Sleep(50);
FindWindow("TForm1", "Form1");
}
return 0;
}
и WinAPI вызывается, и объект можно использовать
Я что-то не вижу в этом коде внешнего завершения потока и проверки освобождения после этого ресурсов. :)
А ресурсы будут аллоцированы в потоке, и большая вероятность, что не освобождены.
Пример: функция FindWindow однозначно аллоцирует, а перед возвращением освобождает внутри себя память. Допустим, поток был прерван при выполнении этой функции. В результате имеем утечку памяти.
Кроме того, где в данном примере синхронизация доступа к объектам, используемым в нескольких потоках?
В частности, строка
fm->ProgressBar1->Position++;
может привести к ошибкам синхронизации.
HANDLE hMapFile = NULL;
LPVOID pMemory = NULL;
int FileSize;
__int64 CheckSumm = -1;
hFileRead = CreateFile(FileName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
if (hFileRead != NULL)
{
hMapFile = CreateFileMapping(hFileRead, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapFile)
{
pMemory = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
FileSize = GetFileSize(hFileRead, 0);
for (int a = 0; a < FileSize; a++)
{
//Делаю необходимое
}
UnmapViewOfFile(pMemory);
}
CloseHandle(hMapFile);
}
CloseHandle(hFileRead);
И лучше всего делать все это в потоке, да?
А сколько можно создать потоков? Как это зависит от типа процессоров и их количества? На что ориентироваться, создавая потоки и сколько их должно быть?
Это вполне можно делать в отдельном потоке. Лучше или нет - зависит от специфики задачи.
Потоков лучше создавать не много. Для твоей задачи целесообразно создать всего два: для UI и для бизнес-логики.
А ресурсы будут аллоцированы в потоке, и большая вероятность, что не освобождены.
Пример: функция FindWindow однозначно аллоцирует, а перед возвращением освобождает внутри себя память. Допустим, поток был прерван при выполнении этой функции. В результате имеем утечку памяти.
Кроме того, где в данном примере синхронизация доступа к объектам, используемым в нескольких потоках?
В частности, строка
fm->ProgressBar1->Position++;
может привести к ошибкам синхронизации.
я не претендую на лавры и овации...
пример был написан за 2 минуты (как в анекдоте: Полковник, выступая с трибуны "т.к. времени мало, буду говорить не думая") только для того что бы показать возможность доступа к объектам и возможности вызова апи-шных ф-ций.
ЗЫ: освобождение памяти, синхронизация и прерывание в данном примере не рассматривается.
ЗЫЗЫ: Я не оспариваю утверждения, что потоки должны синхронизироваться, перед тем как убить поток надо тыщу раз подумать, к чему это может привести, и вообще, что поток из вне не корректно убивать.
А кто говорил, что они невозможны?
ЗЫ: освобождение памяти, синхронизация и прерывание в данном примере не рассматривается.
А мои замечания были как раз именно по этому поводу.
ЗЫЗЫ: Я не оспариваю утверждения, что потоки должны синхронизироваться, перед тем как убить поток надо тыщу раз подумать, к чему это может привести, и вообще, что поток из вне не корректно убивать.
Отлично, значит, делаем на вывод:
Поток не должен завершаться принудительно из вне.
Правильнее проверять в потоках некий объект синхронизации, который устанавливается из основного потока для сигнализации отмены выполнения. Далее основной поток ожидает завершения порожденных.
например:
{
Form1->Caption = "OK!";
}