Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.12.2011, 21:32   #1
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
Печаль WriteFileEx не выполняется асинхронно

Есть определённая задача и хотелось бы её решить с помощью асинхронной записи данных в файл, начал разбираться, накидал примерчик, и делаю вывод что в моём коде WriteFileEx работает синхронно:

Код:
#include <windows.h>
#include <iostream>
#define BUFF_SIZE	    4096

int main(int argc, char *argv[])
{
    HANDLE file = CreateFileA("test.bin",
			      GENERIC_WRITE,
			      0,
			      0,
			      CREATE_ALWAYS,
			      FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
			      0);
    LARGE_INTEGER frq, req_begin, req_end, wrt_begin, wrt_end;
    OVERLAPPED olp;
    char buffer[BUFF_SIZE];

    if (file == INVALID_HANDLE_VALUE)
	return EXIT_FAILURE;

    memset(&frq, 0, sizeof(LARGE_INTEGER));
    memset(&req_begin, 0, sizeof(LARGE_INTEGER));
    memset(&req_end, 0, sizeof(LARGE_INTEGER));
    memset(&wrt_begin, 0, sizeof(LARGE_INTEGER));
    memset(&wrt_end, 0, sizeof(LARGE_INTEGER));
    memset(&olp, 0, sizeof(OVERLAPPED));
    memset(buffer, 0, sizeof(buffer));
    QueryPerformanceFrequency(&frq);

    SetFilePointer(file, BUFF_SIZE, 0, 0);
    SetEndOfFile(file);
    olp.hEvent = CreateEventA(0, true, false, 0);
    QueryPerformanceCounter(&req_begin);

    if (WriteFileEx(file, buffer, BUFF_SIZE, &olp, 0))
    {
	QueryPerformanceCounter(&req_end);
	QueryPerformanceCounter(&wrt_begin);
	WaitForSingleObjectEx(olp.hEvent, 0, false);
	QueryPerformanceCounter(&wrt_end);
    }

    CloseHandle(olp.hEvent);
    CloseHandle(file);

    std::cout << "Request time: " << (double(req_end.QuadPart - req_begin.QuadPart) / frq.QuadPart * 1000)
	      << "ms" << std::endl;

    std::cout << "Write time: " << (double(wrt_end.QuadPart - wrt_begin.QuadPart) / frq.QuadPart * 1000)
	      << "ms" << std::endl;

    return EXIT_SUCCESS;
}
По выводимым данным о времени выполнения операции можно судить что функция WriteFileEx работает много дольше чем ожидание завершения асинхронной операции. При увеличении размера записываемого буфера возврастает и время работы WriteFileEx, что не косвенно говорит о том, что эта функция работает синхронно. Подскажите пожалуйста, что я делаю не так?
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 10:28   #2
rpy3uH
добрый няша
Старожил
 
Аватар для rpy3uH
 
Регистрация: 29.10.2006
Сообщений: 4,804
По умолчанию

суть в том что сама асинхронная операция может завершиться ещё до как функция WriteFileEx вернёт управление. попробуй записать 200 мегабайт данных и сразу всё станет понятно.

при этом записывай данные за одну операцию, выдели буфер размером 200 МБ через функцию VirtualAlloc и запиши за один проход
Код:
#define BUFF_SIZE 1024*1024*200
buffer = VirtualAlloc(0, BUFF_SIZE, ... , ...);
WriteFileEx(file, buffer, BUFF_SIZE, &olp, 0)

Последний раз редактировалось rpy3uH; 28.12.2011 в 10:30.
rpy3uH вне форума Ответить с цитированием
Старый 28.12.2011, 14:19   #3
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

Время работы WriteFileEx при буфере 200МБ равно 1,7 сек., а функции WaitForSingleObjectEx 5 мксек.
Я всё это пробовал, сегодня появится возможность по тестировать это на разных ОС, я уже думаю что дело в этом...
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 15:13   #4
rpy3uH
добрый няша
Старожил
 
Аватар для rpy3uH
 
Регистрация: 29.10.2006
Сообщений: 4,804
По умолчанию

замерь суммарное время
Код:
/////
    QueryPerformanceCounter(&req_begin);
    if (WriteFileEx(file, buffer, BUFF_SIZE, &olp, 0))
    {
	QueryPerformanceCounter(&req_end);
	QueryPerformanceCounter(&wrt_begin);
	WaitForSingleObjectEx(olp.hEvent, 0, false);
	QueryPerformanceCounter(&wrt_end);
    }
/////
суммарное время должно быть равно сумме req_* и wrt_*
rpy3uH вне форума Ответить с цитированием
Старый 28.12.2011, 15:43   #5
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

Замерил суммарное время, да, оно соответствует сумме wrt_* и req_*. Попробовал на WinXP и Win7 - ситуация везде одинаковая.
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 16:23   #6
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Код:
WriteFileEx(file, buffer, BUFF_SIZE, &olp, 0)
имхо, вы не даёте ей шансов выполнится асинхронно, т.к. lpCompletionRoutine у вас не задана.

Код:
WaitForSingleObjectEx(olp.hEvent, 0, false);
Цитата:
The WriteFileEx function ignores the OVERLAPPED structure's hEvent member. An application is free to use that member for its own purposes in the context of a WriteFileEx call. WriteFileEx signals completion of its writing operation by calling, or queuing a call to, the completion routine pointed to by lpCompletionRoutine, so it does not need an event handle.
хотя, судя по тому, что код таки выходит из ожидания, мсдн немного лукавит. А может, это следствие того, что lpCompletionRoutine не задана.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 28.12.2011, 16:34   #7
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

Я пробовал и с этим lpCompletionRoutine, но этот параметр _in_opt. Если этот параметр указан, то после перехода потока в тревожное состояние (WaitForSingleObjectEx(..., ..., true)), программа начнёт выполнять очередь APC, куда и будет занесён этот колбэк. Иначе говоря, есть он или нет, разницы нету. Уже сомневаясь во всех моих пониманиях, знаниях и догадках, я попробовал его указать: колбэк вызывается после перехода в тревожное состояние потока, но ситуация осталась прежняя: WriteFileEx работает синхронно.
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 16:48   #8
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> Иначе говоря, есть он или нет, разницы нету.

хм, если его нет, у WriteFileEx() просто нет шансов сообщить вам что-либо асинхронно.

Если же lpCompletionRoutine указан, то вы:

1) вызываете WriteFileEx()
2) продолжаете заниматься своими делами
3) когда делать совсем уж нечего, переводите поток в alertable wait state и получаете каллбэк

Вот такая разница. Впрочем, WriteFileEx() не обязан выполнятся асинхронно, например, если вы пишете в компресированный файл на NTFS, любая запись будет выполнятся синхронно.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 28.12.2011, 17:26   #9
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

Цитата:
м, если его нет, у WriteFileEx() просто нет шансов сообщить вам что-либо асинхронно
Вы не до конца понимаете работы этого механизма, окончание работы записи в файл мне асинхронно сообщается по olp.hEvent: если он в сигнальном состоянии, то асинхронная запись в файл закончена. Я могу не пользоваться колбэком, если в этом нет необходимости. И могу пользоваться обычной функцией WaitForSingleObject, дожидаясь сигнального состояния olp.hEvent.

Цитата:
например, если вы пишете в компресированный файл на NTFS, любая запись будет выполнятся синхронно.
Как видите, обычный файл:
Код:
HANDLE file = CreateFileA("test.bin",
			      GENERIC_WRITE,
			      0,
			      0,
			      CREATE_ALWAYS,
			      FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED,
			      0);
Все условия, приведённые в вашей ссылке - соблюдены:
1)Сжатие - отсутствует
2)Шифрование файловой системы NTFS - отсутствует
3)Расширение файла - учтено в коде:
Код:
SetFilePointer(file, BUFF_SIZE, 0, 0);
    SetEndOfFile(file);
5)Не используйте кэш - FILE_FLAG_NO_BUFFERING
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 17:32   #10
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

Хочу ещё добавить, что если вместо функции WriteFileEx использовать WriteFile, то она возвращает false, а GetLastError == ERROR_IO_PENDING, что означает выполнение асинхронной операции, хотя наряду с этим функция WriteFile возвращает управление только после того, как все данные в файл запишутся. Опять синхронный вариант.
IkSin вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Не выполняется макрос allichka Microsoft Office Excel 5 19.05.2011 14:47
не выполняется условие Link12 Общие вопросы C/C++ 6 30.03.2010 19:36
Странное поведение WriteFile / WriteFileEx (асинхронный I/O) besserebrenik Win Api 0 22.02.2010 20:37
Компилируется,но не выполняется. Lunex.08 C++ Builder 6 19.11.2009 12:17