Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

TerminateProcess


Страницы:   1 2 3 4 5 6 7

Суслик ©   (2005-04-25 14:53:00) 

Добрый день.

Есть такой псевдокод:

... запись в файл 200 мб из памяти
sleep(500);
TerminateProcess(GetCurrentProcess);


Вопрос: почему система ждет, когда файл запишется и только потом приложение закрывается? Вернее, почему файл оказывается записанным?

ЗЫ. win2000 server, диски ntfs и fat32.


Sha   (2005-04-26 10:43:00) [101]

> mgcr ©   (26.04.05 10:31) [35]
> И потом, чем тебе мой или Алекса способ не нравится ?

Тем, что способ [27] не гарантирует надежной работы.


mgcr   (2005-04-26 10:31:00) [102]

Суслик ©   (25.04.05 18:51) [29]

Тогда колись дальше: сколько должно быть таких "больших файлов", как они организованы (есть ли ключевые атрибуты и т.д.), как регулярно происходит запись.

От транзакций тебе все равно никуда не деться.
И потом, чем тебе мой или Алекса способ не нравится ?


Sha   (2005-04-26 10:26:00) [103]

В смысле "страниц в памяти" ?


Sha   (2005-04-26 10:25:00) [104]

> Alex Konshin ©   (26.04.05 09:47) [31]
> Весь твой файл нужно открывать без кеширования
> или, еще лучше, организовать memory mapping.

Разве memory mapping гарантирует обновление секторов файла
в порядке обновления секторов в кеше?


Alex Konshin   (2005-04-26 10:01:00) [105]

Какого рода изменения происходят в данных?
Что-то изменяется или только добавляется?

Кстати, очень простую базу в своем файле можно организовать используя то обстоятельство, что можно создавать свои win32  регистри файлы и подключать их к системному регистри. Кстати, надо бы проверить, когда именно происходит изменение состояния регистри, при каждой операции или при закрытии ключа.
То есть, если изменения очень маленькие, то можно использовать регистри как древовидную базу данных. Ну, это, скажете вы, каждый знает. Но не каждый помнит о том, что можно иметь регистри в своем файле.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regloadkey.asp


Alex Konshin   (2005-04-26 09:47:00) [106]

Ты все 3M перезаписываешь каждый раз?
Почему нельзя писать в другой файл?
Подозреваю, что ты хочешь иметь некую маленькую базу данных.
Могу предложить организовать внутри этого своего файла страничную организацию и изменения всегда писать в другую страницу кроме корневой страницы (твой FAT), которая должна записываться последней. Если размер страницы в файле будет равен размеру сектора (т.е. 512), то как раз и будет гарантироваться транзакциональность изменения. Т.к. 512 байт не достаточно для FAT файла размером 3M, то придется делать его двухуровневым. Т.е. выглядеть должно так:
0-й гиперблок содержит номера блоков, где сидят соответствующие гиперблоки.
Гиперблоки содержат уже номера блоков самого логического файла.

Запись изменений всегда должна происходить в порядке снизу вверх. Т.е. сначала записываешь измененный или новый сектор файла, причем этот сектор обязательно должен быть из списка свободных, ни в коем случае нельзя заменять блок на месте. Потом изменяешь соответствующий гиперблок (пишешь в него номер нового сектора данных) и опять-таки пишешь его на новое место. И, наконец, пишешь корневой гипреблок, в котором изменен номер только что записанного гиперблока, вот его уже пишешь по месту. Весь твой файл нужно открывать без кеширования или, еще лучше, организовать memory mapping.

Собственно, я упрощенно описал принцип работы транзакциональной файловой системы. Те же structured storage работают также. Если сделаешь так, то будет гарантироваться целостность логического файла не зависимо от того, обеспечивает или нет транзакциональность сама файловая система.


alpet   (2005-04-25 19:17:00) [107]

Самая лучшая защита - CRC. В твоем случае не обязательно хэшировать весь файл, но вполне возможно хэшировать его окончание. Если идти твоим путем - можно вести лог-файл в который будут записываться имена файлов успешно записанных на диск, причем запись имен вести через некоторое время (5-10 сек после выполнения FlushFileBuffersEx) что бы была хоть какая-то гарантия, что и аппаратные буфера жесткого диска записались.


Суслик   (2005-04-25 18:51:00) [108]


> [27] mgcr ©   (25.04.05 18:41)


> Если очень хочется помучиться, то заведи два файла (небольших,
> по байту или меньше), перед


Хочу мучаться ерундой, не осуждай уж. Серьезно.

Чем такой вариант хуже?

1. При записи файл данных "a.dat" переименовывается в "a.old"
2. В файл "a.dat" ведется запись новых данных.
3. Происходит сброс данных в файл "a.dat".
4. Файл "a.old" удаляется.

При старте я будут знать дописался ли файл или нет. Если есть old, значит не дописался. Если нет, то значит все ок (т.е. я даже не знаю, про то, что что-то случилось)


Суслик   (2005-04-25 18:47:00) [109]


> [25] mgcr ©   (25.04.05 18:31)


> А зачем надо гонять такие мегабайты туда-сюда, кстати ?

надо, чтобы программа работала и хранила без всяких сторонних разработок, типа серверов и пр - только файлы. Структура данных чрезвычайно проста - большой бинарный поток. На самом деле он намного меньше - порядка 1-2 мб, просто используя 100мб - легче поймать момент, когда запись не завершена.

Я смотрел fireBird. Мне не равится там ситуация с его поддержкой, и в частности с документированностью. Да и вообще - из пушки по ...

Задача просто - раз в минуту сохранять макс. до 3 мб памяти в одинфайл. Нужно сделать так, чтогбы ничего не потерялось, т.е. при следующей загрузке:
1. Либо оказался корректный новый файл, при этом информация о сбое отсутстует.
2. Либо оказался корректный старый файл, при этом присутствует информация о сбое.
1


mgcr   (2005-04-25 18:41:00) [110]


> Собственно вопрос с terminateProcess слабо относится к моей
> задаче. Я просто исходно по наивности думал, что таким образом
> смогу смоделировать сбой :))) не вышло :)))


Кнопка Reset.

Но опять же, извини, не вижу смысла в страдании подобной ерундой. Если ты обмениваешься большими объемами, то средствами файловой системы я полагаю, ты не добьешься поведения "либо полностью старое состояние файла, либо полностью новое". То есть, файловые системы, они, некоторые, транзакционные, но ихние транзакции к пользовательским данным не имеют никакого отношения.

Если очень хочется помучиться, то заведи два файла (небольших, по байту или меньше), перед началом записи большого объема запиши первый файл, означающий "запись данных начата" (и закрой его, сбросив буфер), по успешному окончании записи объема запиши второй файл, означающий "запись данных завершена", а первый удали. Тогда при старте ты будешь знать, в каком состоянии находятся данные твоего большого объема.
Но лучше СУБД использовать - там этот механизм уже успешно реализован.


alpet   (2005-04-25 18:33:00) [111]

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

Это проще промоделировать в реальности :=)  
Во всяком случае чтобы спровоцировать ошибку в твоем случае, надо попробывать принудительно высвободить страницы памяти из первого потока (VirtualFree), в тот момент когда второй будет пытаться их записывать.


mgcr   (2005-04-25 18:31:00) [112]


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


UPS - рулез фарева. NTFS - рулез фарева. NTFS+UPS двойной рулез.

А зачем надо гонять такие мегабайты туда-сюда, кстати ?


alpet   (2005-04-25 18:30:00) [113]

>> TerminateProcess(GetCurrentProcess, 0);
Вот из-за этой строки все и может развиваться согласно [8]. Выполни вместо этого:

with TFileThread.Create(true) do
 begin
  Resume();
  Sleep (500);
  nStart := GetTickCount;
  TerminateThread (Handle);
 end;
WaitForSingleObject (handle, 5000);
nStart := GetTickCount - nStart;
ShowMessage (IntToStr (nStart) ); // show waiting delay

 
Тогда поток должен поидее завершиться сразу.


Суслик   (2005-04-25 18:24:00) [114]

Хотел бы еще упомянуть про то, чего я добиваюсь.

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

Собственно вопрос с terminateProcess слабо относится к моей задаче. Я просто исходно по наивности думал, что таким образом смогу смоделировать сбой :))) не вышло :)))

Теперь вопрос про terminateProcess представляет скорее познавательный интерес.


Суслик   (2005-04-25 18:13:00) [115]

Господа. Я был неправ. Дома у меня работает несколько иначе чем на работе.
Дома (2000 server) - при terminateProcess ждет пока весь файл не будет
записан
На работке (2000 prof) - при terminateProcess сразу выходит, но файл еще потом некоторове вермя недоступен, но в итоге записывается правильной информацией.

Мой код.
модуль

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TForm1 = class(TForm)
   Button1: TButton;
   Memo1: TMemo;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

const
  cLen = 100*1024*1024;
var
  fBuffer: packed array[0..cLen-1] of byte;

type
  TFileThread = class(TThread)
     protected procedure Execute(); override;
  end;

procedure TFileThread.Execute();
var
  kFS: TFileStream;
begin
  kFS := TFileStream.Create('d:\temp\data', fmCreate or fmShareExclusive);
  try
     kFS.WriteBuffer(fBuffer, cLen);
  finally
     kFS.Free();
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  kM: String;
begin
  // записываем первый файл
  FillChar(fBuffer, cLen, ord('0'));
  DateTimeToString(kM, 'начало записи файла 1 = yyyy-mm-dd hh:nn:zzz', Now());
  Memo1.Lines.Add(kM);
  with TFileThread.Create(true) do
  begin
     Resume();
     WaitFor();
     Free();
  end;
  DateTimeToString(kM, 'конец записи файла 1 = yyyy-mm-dd hh:nn:zzz', Now());
  Memo1.Lines.Add(kM);

  // перезаписываем файл
  FillChar(fBuffer, cLen, ord('1'));
  DateTimeToString(kM, 'начало записи файла 2 = yyyy-mm-dd hh:nn:zzz', Now());
  Memo1.Lines.Add(kM);
  with TFileThread.Create(true) do
  begin
     Resume();
  end;

  Sleep(500);

  DateTimeToString(kM, 'вызов GetCurrentProcess = yyyy-mm-dd hh:nn:zzz', Now());
  Memo1.Lines.Add(kM);

  TerminateProcess(GetCurrentProcess, 0);
end;

end.


dfm

object Form1: TForm1
 Left = 396
 Top = 106
 Width = 446
 Height = 403
 Caption = 'write test'
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = 'MS Sans Serif'
 Font.Style = []
 OldCreateOrder = False
 PixelsPerInch = 96
 TextHeight = 13
 object Button1: TButton
   Left = 8
   Top = 24
   Width = 75
   Height = 25
   Caption = 'write'
   TabOrder = 0
   OnClick = Button1Click
 end
 object Memo1: TMemo
   Left = 104
   Top = 24
   Width = 329
   Height = 345
   TabOrder = 1
 end
end


mgcr   (2005-04-25 17:52:00) [116]

Суслик ©   (25.04.05 17:41) [20]

Ты бы код записи что ли привел. А то гадаем на кофейной гуще.


Суслик   (2005-04-25 17:41:00) [117]


>  [19] mgcr ©   (25.04.05 17:25)


> If the application does not force the operating system to
>

Игорь, насколько я понимаю нефорсить запись файла, является умолчательнымповедением. Я не прав? Какой конкретно флаг приводит к отложенной записи?


mgcr   (2005-04-25 17:25:00) [118]


> If the application does not force the operating system to
> write the buffer to disk before closing the file


Дима, а ты уверен, что файл открывается с отложенной записью ? :)


alpet   (2005-04-25 17:11:00) [119]

mgcr ©   (25.04.05 17:04) [16]

Надо будет изучить вопрос. В любом случае выгрузка страниц физической памяти на диск должна выполнятся при ее не хватке.


alpet   (2005-04-25 17:07:00) [120]

Для принудительной выгрузки буферов надо вызывать FlushFileBuffers. Интересно если попываться завершить поток в момент выполнения функции - система уничтожит его до завершения записи системного кэша? Если в функции осуществляется обработка системного вызова - по идее не должно. Можно сравнить время ожидания WaitForSingleObject (hThread) с FlushFileBuffers и без оного.


Страницы:   1 2 3 4 5 6 7

Наверх

Титульная страница Поиск, карта сайта Написать письмо