Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Асинхронная запись в файлы 
:(
    Опции темы
Lazin
Дата 16.4.2009, 09:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



В общем, есть приложение, которое записывает данные в файлы(много их) асинхронно, время от времени оно выдает сообщение об ошибке: "The I/O operation has been aborted because of either a thread exit or an application request" и продолжает работать дальше...
К чему-бы это?
PM MAIL Skype GTalk   Вверх
GoldFinch
Дата 16.4.2009, 09:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: 2
Всего: 26



к отладчику?
PM MAIL ICQ   Вверх
Lazin
Дата 16.4.2009, 09:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



я не могу это воспроизвести, это происходит после нескольких суток работы приложения, поэтому я и спрашиваю, что может вызвать подобную ошибку (GetLastError = 995)
PM MAIL Skype GTalk   Вверх
Anikmar
Дата 16.4.2009, 10:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2513
Регистрация: 26.11.2006
Где: Санкт-Петербург

Репутация: нет
Всего: 59



Мне так кажется не проверяется результат команды записи в файл. Если при неблагоприятном стечении обстоятельств запись в файл задержалась, а поток прекратил работу (считая, что все записал) будет эта ошибка, насколько я понял.
PM MAIL ICQ   Вверх
azesmcar
Дата 16.4.2009, 10:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Lazin
Может быть вызвано неправильной синхронизацией потоков. Это ошибка вроде означает что программа пытается прочитать из файла, который закрыт (или может заблокирован??).
PM   Вверх
Alexeis
Дата 16.4.2009, 10:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 7
Всего: 459



  Хотелось бы сначала выяснить могут ли в этой программе 2 потока обращаться к одному файлу.
Еще такое предположение, если событие редкое может файл блокируется антивирусом или службой индексирования?


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Lazin
Дата 16.4.2009, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



файлы открываются в режиме FILE_SHARE_READ | FILE_SHARE_WRITE а так-же FILE_FLAG_OVERLAPPED
разные потоки могут вызывать WriteFile для одного и того-же файла, данные которые должны быть записаны, удаляются после того, как на порт завершения будет добавлен пакет завершения сигнализирующий о том, что все данные записаны
PM MAIL Skype GTalk   Вверх
GremlinProg
Дата 16.4.2009, 13:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



по-русски, 995 ошибка звучит так: "Операция ввода/вывода была прервана из-за завершения потока команд или по запросу приложения. "

Lazin, у тебя ни где не вызывается случайно CancelIO?
это по-моему, как раз второй случай - "...по запросу приложения"


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Lazin
Дата 16.4.2009, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Цитата(GremlinProg @  16.4.2009,  13:07 Найти цитируемый пост)
у тебя ни где не вызывается случайно CancelIO?

может-ли такое произойти, поток вызывает WriteFile для асинхронной записи данных, сразу после этого другой поток, или этот-же вызывает TerminateThread? Просто в этом приложении моя только библиотека, которая выполняет файловые операции, что там происходит для меня загадка.
PM MAIL Skype GTalk   Вверх
xvr
Дата 16.4.2009, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 40
Всего: 223



Цитата(Lazin @ 16.4.2009,  13:48)
Цитата(GremlinProg @  16.4.2009,  13:07 Найти цитируемый пост)
у тебя ни где не вызывается случайно CancelIO?

может-ли такое произойти, поток вызывает WriteFile для асинхронной записи данных, сразу после этого другой поток, или этот-же вызывает TerminateThread? 

Да
Цитата

Просто в этом приложении моя только библиотека, которая выполняет файловые операции, что там происходит для меня загадка.
А кто выдает ошибку - твоя библиотека или кто то еще?

PM MAIL   Вверх
GremlinProg
Дата 16.4.2009, 14:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Lazin @  16.4.2009,  15:48 Найти цитируемый пост)
может-ли такое произойти, поток вызывает WriteFile для асинхронной записи данных, сразу после этого другой поток, или этот-же вызывает TerminateThread?

а принципе - да, если очередь не пуста, а поток завершается, то оставшиеся команды I/O теряются, но по идее, чтобы отловить эту ошибку нужен по крайней мере не полная асинхронная операция, ты используешь простой или расширенный интерфейс? WriteFile или WriteFileEx?

у меня есть два варианта возможного решения:
1. в Red/WriteFile а четвертый параметр передавать NULL (это в некотором роде подсказка оси, что в данный момент даже пытаться выполнять операцию не надо)
2. использовать расширенный интерфейс и ввести счетчик операций, тогда перед завершением потока можно убедиться, что очередь не пуста и подождать, если это не так:
Код

::EnterCriticalSection(...);
while( counter ){
  ::LeaveCriticalSection(...);
  ::SleepEx(INFINITE,TRUE);
  ::EnterCriticalSection(...);
}
::LeaveCriticalSection(...);

а в callback'е завершения I/O, уменьшать этот счетчик:
Код

VOID CALLBACK FileIOCompletionRoutine(DWORD dwErrorCode,DWORD dwNumberOfBytesTransfered,LPOVERLAPPED lpOverlapped){
...
::EnterCriticalSection(...);
--counter;
::LeaveCriticalSection(...);
...
}

тогда перед самой чтением/записью, этот счетчик увеличить:
Код

::EnterCriticalSection(...);
++counter;
::LeaveCriticalSection(...);
::WriteFileEx(...);


Добавлено через 6 минут и 46 секунд
можно синхронный счетчик использовать InterlockedIncrement/Decrement


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Lazin
Дата 16.4.2009, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Цитата(xvr @  16.4.2009,  14:05 Найти цитируемый пост)
А кто выдает ошибку - твоя библиотека или кто то еще?

ошибку я получаю в своей библиотеке
все работает примерно так:
Код

void my_class :: function( data_ptr data )
{
    EnterCriticalSection(&my_cs);
    my_queue.enqueue( deep_copy(data) ); //копируем данные
    if ( can_write() )
    {
        data_ptr p = my_queue.dequeue();//извлекаем данные
        DWORD error_code = WriteFile(p, p.size(), .... new my_overlapped(p, file_pos...) );
        //my_overlapped - структура унаследованая от 
        //OVERLAPPED, которая хранит данные, необходимые для 
        //того, что-бы обработать событие завершения записи в файл
        if (error_code != ERROR_IO_PENDING) --обработка ошибок
    }
    LeaveCriticalSection(&my_cs);
}
//это выполняется в отдельном потоке
void my_class :: thread_proc()
{
    while (true)
    {
       //ожидание событий на порте завершения
        DWORD res = GetQueuedCompletionStatus(....);
        //здесь я получаю результат выполнения ранее начатой асинхронной операции
        //через структуру OVERLAPPED переданую в ф-ю WriteFile
        //и если очередь my_queue не пуста я начинаю следующую операцию записи
        --обработка ошибок
        --обработка события
        data_ptr p = my_queue.dequeue();
        if (p)
        {
            WriteFile(p, p.size(), .... new my_overlapped(p, file_pos...) );
            ...
        }
    }
}

это что-то вроде псевдокода, но суть должна быть понятна

Добавлено @ 14:42
зы
я там использую порт завершения

Добавлено @ 14:48
я пока вижу такое решение: не вызывать ф-ю WriteFile из потока пользователя вообще, вместо этого вызывать PostQueuedCompletionStatus и передавать туда данные, приняв которые, мой поток начал-бы выгребать данные из очереди и писать их в файл

Это сообщение отредактировал(а) Lazin - 16.4.2009, 14:58
PM MAIL Skype GTalk   Вверх
GremlinProg
Дата 16.4.2009, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



а что мешает сначала заполнить очередь,
а потом подождать завершения всех операций?

у тебя получается так, что скорость передачи данных в порт напрямую зависит от времени ожидания GetQueuedCompletionStatus
и практически не зависит от скорости поступления данных (не используется разрешающая способность самой очереди ввода/вывода)

попробуй разделить:
если есть данные в очереди - пиши их в порт
кончились - жди завершения операций
появились - снова пиши и т.д.

а принудительно уходи в ожидание только при отказе WriteFile, когда квота заканчивается




--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Lazin
Дата 16.4.2009, 22:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 8
Всего: 154



Цитата(GremlinProg @  16.4.2009,  18:41 Найти цитируемый пост)
а что мешает сначала заполнить очередь,
а потом подождать завершения всех операций?

мне нужно, что-бы даннве по возможности не накапливались в памяти

я возможно плохо все описал, попробую исправиться)
у меня есть очередь, очередь состоит из буферов фикс. размера, скажем, 64кб
пользовательское приложение вызывает ф-ю моей библиотеки, эта ф-я дописывает данные в конец последнего буфера в очереди, если его нет, то она его создает, далее, если в данные момент нет не завершенных операций записи в файл, она начинает новую, вызывая WriteFile. Соответственно в ф-ю WriteFile передаются все 64kb (первый в очереди буфер).
В этот момент данные еще не записаны, если пользовательское приложение снова вызовет мою ф-ю, то данные будут добавлены в буфер, но ф-я WriteFile вызвана не будет, так-как предидущая операция записи еще не завершена, считается что он "занят".
Рабочий поток моей библиотеки ждет на порте завершения, и когда завершается очередная операция записи он освобождает 64кб буфер, а затем пытается извлечь из очереди следующий буфер и начать записывать его. 
Пока есть незавершенные операции записи (это контролируется) файл не будет закрыт. Единственное что у меня может пойти не так, это поток пользовательского приложения может начать операцию записи(вызвав WriteFile) и сразу завершиться (вполне вероятно что даже аварийно, вызвав ExitThread или TerminateThread...

Это сообщение отредактировал(а) Lazin - 16.4.2009, 22:57
PM MAIL Skype GTalk   Вверх
GremlinProg
Дата 16.4.2009, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Lazin @  17.4.2009,  00:51 Найти цитируемый пост)
я возможно неправильно выразился 

нет, я все понял, наверное, сам неверно выразился, смешав 2 очереди )

главное, что я выделяю - это то, что асинхронной ввод/вывод уже имеет очередь,
которую можно и даже нужно задействовать, иначе - зачем его вообще использовать?
запись в файл при таком раскладе можно осуществлять и синхронно прямо в твоем потоке, ничего от этого не изменится

мне кажется, что очередь, которую ты строишь дополнительно - лишняя нагрузка на my_class :: function,
если ты хотел отвязаться от ожидания завершения записи на диск при вызове function, то ты от него избавился, но прибавил в нагрузку практически тот же самый вес, формируя дополнительную очередь

тут достаточно просто асинхронно писать в файл, учитывая общее число байт (чтобы не выйти из потока преждевременно)

достаточно дополнить интерфейс библиотеки функцией flush, в которой просто подождать завершения всех операций (неважно каким способом)
поток - нужен, но только на стороне пользователя (как я понял, он там уже есть)
если flush невозможно встроить на стороне пользователя, то его можно вызвать в DllMain, перед отсоединением потока
тогда ошибок быть не должно


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0666 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.