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

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

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

Восстановить пароль

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

Ответ
 
Опции темы Поиск в этой теме
Старый 28.12.2011, 17:39   #11
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> Вы не до конца понимаете работы этого механизма

вполне возможно, т.к. механизм сложный.

> окончание работы записи в файл мне асинхронно сообщается по olp.hEvent

в мсдн сказано, что olp.hEvent не используется. Я склонен верить мсдн. Ждать можно любое событие.

> Я могу не пользоваться колбэком, если в этом нет необходимости

не уверен. Пользуйтесь тогда WriteFile(), оно точно так же отлично умеет записывать данные асинхронно, без колбэков.

> Не используйте кэш

это где такое написано? В мсдн сказано, что если вы зачем-то используете FILE_FLAG_NO_BUFFERING, то там куча ограничений. О том, что его надо использовать — нигде ни слова.

Я вот не поленился, набросал простой проект (сорри, привычней на дельфи):

Код:
program
  writeFex;

{$APPTYPE CONSOLE}

uses
  Windows, unaUtils;

const
  sz	= 1024 * 1024 * 30;

var
  mt: uint64;
  t1, t2: uint64;

procedure callback(dwErrorCode: DWORD; dwNumberOfBytesTransfered: DWORD; var lpOverlapped: OVERLAPPED); stdcall;
begin
  t2 := timeElapsedU(mt);
  writeln('callback');
end;


var
  OL: OVERLAPPED;
  f: thandle;
  buf: pointer;
  E: tHandle;
begin
  DeleteFile('C:\killme.dat');
  //
  E := CreateEvent(nil, false, false, nil);
  //
  f := CreateFile('C:\killme.dat', GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
  if (INVALID_HANDLE_VALUE <> f) then begin
    //
    fillChar(OL, sizeof(OL), #0);
    //
    GetMem(buf, sz);
    //
    mt := timeMarkU();
    if (WriteFileEx(f, buf, sz, OL, @callback)) then begin
      //
      t1 := timeElapsedU(mt);
      writeLn('WriteFileEx() returned TRUE, GLE=', GetLastError());
      //
      WaitForSingleObjectEx(E, 1000, true);
    end
    else
      writeLn('WriteFileEx() fail with error ', GetLastError());
  end;
  //
  writeln('t1=', t1, ';  t2=', t2);
end.
Как и ожидалось, оно мне вывело:

Цитата:
WriteFileEx() returned TRUE, GLE=0
callback
t1=15; t2=453
что означает, что WriteFileEx() вернуло управление через 15 мс, а коллбэк вызвался через 453 мс. Я склонен полагать, что WriteFileEx() отработало асинхронно.

UDP: добавил в свой код FILE_FLAG_NO_BUFFERING, и оно начало работать синхронно. Думаю, в этом можеть быть причина.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 28.12.2011 в 17:45.
veniside вне форума Ответить с цитированием
Старый 28.12.2011, 18:22   #12
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

[QOUTE]в мсдн сказано, что olp.hEvent не используется. Я склонен верить мсдн. Ждать можно любое событие.[/QUOTE]
мм, если точнее, это функцией WriteFileEx он не используется, т.е. другими словами мы можем создать в этой переменной Event и быть уверенными что хэндл эвента в этой функции не изменится.

Цитата:
это где такое написано? В мсдн сказано, что если вы зачем-то используете FILE_FLAG_NO_BUFFERING, то там куча ограничений. О том, что его надо использовать — нигде ни слова.
Вот так это у них написано, я понял что для асинхронной его надо юзать обязательно:
Цитата:
Не используйте кэш
Флаг FILE_FLAG_NO_BUFFERING имеет наиболее влияют на поведение Файловая система для асинхронной операции. Это лучший способ гарантировать что действительно асинхронных запросов ввода-вывода. Он указывает, что файловая система Чтобы не использовать любой кэш механизм вообще.
Цитата:
Я вот не поленился, набросал простой проект (сорри, привычней на дельфи):
За что вам спасибо, но ваш пример совсем не гарантирует выполнения асинхронной записи:
1) Вы записываете 30 МБ, это примерно 8мс на дешёвых винтах.
2) Вы используете не достаточные средства для измерений времени:
Код:
 mt := timeMarkU();
 if (WriteFileEx(f, buf, sz, OL, @callback)) then begin
      t1 := timeElapsedU(mt);
Помоему это обёрнутое использование GetTickCount(), дискретность которого 15 мс., соответственно за ваше показанное время (15мс) запись вполне могла успеть пройти синхронно.
3) А вот тут чего вы ждёте?
Код:
WaitForSingleObjectEx(E, 1000, true);
У вас происходит выход по таймауту, по пробуйте поставить туда нолик и ваша программа будет ждать бесконечно. Собственно после выхода по таймауту у вас вызывается колбэк
Код:
procedure callback(dwErrorCode: DWORD; dwNumberOfBytesTransfered: DWORD; var lpOverlapped: OVERLAPPED); stdcall;
begin
  t2 := timeElapsedU(mt);
  writeln('callback');
end;
где вы замеряете непонятно какое время t2.

нужно OL.hEvent приравнять E и ждать с таймаутом 0 (INFINITE), только так получим правильные результаты.
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 18:25   #13
IkSin
Новичок
Джуниор
 
Регистрация: 27.12.2011
Сообщений: 9
По умолчанию

FILE_FLAG_NO_BUFFERING - увеличивает время записи в файл, потому что буферизации нет. Вам кажется что начало работать синхронно, действительно же увеличилось время записи.
IkSin вне форума Ответить с цитированием
Старый 28.12.2011, 18:42   #14
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

> мы можем создать в этой переменной Event и быть уверенными что хэндл эвента в этой функции не изменится.

с этим согласен.

> Вы записываете 30 МБ, это примерно 8мс на дешёвых винтах.

ну вот такой у меня медленный винт ) Больше 32 мб за раз оно не пишет, кстати. Возвращает ERROR_NO_SYSTEM_RESOURCES(1450).

> Помоему это обёрнутое использование GetTickCount()

нет, но это не важно.

> А вот тут чего вы ждёте?

это совершенно не важно, главное, что поток ушёл в alertable wait state.

> Собственно после выхода по таймауту у вас вызывается колбэк

нет. Коллбек вызывается во время ожидания, а не после.

> непонятно какое время t2

очень даже понятно — время, прошедшее от вызова WriteFileEx() до попадания в колбэк, т.е. то время, которое потребовалось WriteFileEx() для завершения записи.

> нужно OL.hEvent приравнять E

нафига?

> ждать с таймаутом 0 (INFINITE), только так получим правильные результаты.

ну ждал я с INFINITE, результат тот же, естсетвенно.

> действительно же увеличилось время записи

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

Вот мой код, по аналогии с вашим:
Код:
#include <windows.h>
#include <iostream>
#define BUFF_SIZE	    1024*1024*32

void CALLBACK writeCallback(DWORD error,
                            DWORD transfered,
                            OVERLAPPED *overlapped)
{
}

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

    if (!buffer)
        return EXIT_FAILURE;

    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));
    SetFilePointer(file, BUFF_SIZE, 0, 0);
    SetEndOfFile(file);
    QueryPerformanceFrequency(&frq);
    QueryPerformanceCounter(&req_begin);

    if (WriteFileEx(file, buffer, BUFF_SIZE, &olp, writeCallback))
    {
        QueryPerformanceCounter(&req_end);
        QueryPerformanceCounter(&wrt_begin);
        WaitForSingleObjectEx(event, 0, true);
        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;
}
Результат:
Request time: 400.00ms
Write time: 0.02ms

а в чём разница, мне не понятно. Может быть вы мне вышлите скомпилированный экзешничек, а я ваш код попробую у себя запустить?
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