Форум: "WinAPI";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
ВнизTerminateProcess Найти похожие ветки
← →
Суслик © (2005-04-25 14:53) [0]Добрый день.
Есть такой псевдокод:... запись в файл 200 мб из памяти
sleep(500);
TerminateProcess(GetCurrentProcess);
Вопрос: почему система ждет, когда файл запишется и только потом приложение закрывается? Вернее, почему файл оказывается записанным?
ЗЫ. win2000 server, диски ntfs и fat32.
← →
Digitman © (2005-04-25 14:55) [1]
> почему файл оказывается записанным?
а почему он не должен быть записанным в дан.случае ?
← →
Суслик © (2005-04-25 15:14) [2]
> [1] Digitman © (25.04.05 14:55)
ну вроде процесс должен прекратиться.
Кто файл дописывает? Ядро? Какой тут механизм?
Файл - объект ядра. Логично предположить, что процесс дав команду ядру записать в файл данные, уже не может повлиять на процесс записи - ядро данные запишет. Но запись то идет из памяти, а память принадлежит процессу, т.е. если процесс во время записи в файл "умрет", то и умрет его память. Откуда ядро берет данные для записи?
← →
alpet © (2005-04-25 15:19) [3]Все бы хорошо, да только стандартные функции записи в файл являются синхронными, и после вызова их можно быть уверенным что данные либо в файле, либо в системном кэше.
← →
mgcr © (2005-04-25 15:21) [4]
> Какой тут механизм?
CloseHandle
> Но запись то идет из памяти, а память принадлежит процессу,
> т.е. если процесс во время записи в файл "умрет", то и умрет
> его память. Откуда ядро берет данные для записи?
Из кэша.
Память не принадлежит процессу. Память принадлежит диспетчеру памяти и только.
← →
Суслик © (2005-04-25 15:28) [5]
> [3] alpet © (25.04.05 15:19)
эттта, виноват, неверный пример написал (упростил сильно) - запись в файл у меня идет в дополнительном потоке, а прерывается процесс в главном потоке. Т.е. про синхронность здесь говорить не приходится.
> [4] mgcr © (25.04.05 15:21)
Игорь, я знаю, что при TermProcess происход CloseHandle для всех объектов, в том числе и для файлов - это явно описано в MSDN. Но я не понимаю, если я (процесс) закрыл handle у файла, почему меня (процесс) кто-то "держит". Т.е. такое ощущение (используя секундомер) меня держар ровно пока файл не запишет все данные из моей памяти. Вот я и спрашиваю - какой тут механизм. Может быть такое, что файл ссылается на процесс, и пока не допишется до конца не делает процессу Closehandle тем самым удерживая процесс в памяти?
← →
mgcr © (2005-04-25 15:46) [6]Суслик © (25.04.05 15:28) [5]
> Но я не понимаю, если я (процесс) закрыл handle у файла,
> почему меня (процесс) кто-то "держит".
Пока Handle не закроется. А закрытие такого Handle требует сброса кэша. Пока он сбрасывается, Close тебя не отпускает.
← →
Суслик © (2005-04-25 15:57) [7]
> закрытие такого Handle требует сброса кэша. Пока он сбрасывается,
> Close тебя не отпускает.
тогда как это соотносится с?
If there is data in the internal buffer when the file is closed, the operating system does not automatically write the contents of the buffer to the disk before closing the file. If the application does not force the operating system to write the buffer to disk before closing the file, the caching algorithm determines when the buffer is written.
источник http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/file_management_functions.asp
Кто-все таки процесс держит?
← →
alpet © (2005-04-25 16:04) [8]Твой процесс держит система не до тех пор "пока запишется файл", а до тех пор пока не осуществится копирование заказанного блока памяти в системный кэш. С учетом того что кэш (при ограниченном объеме оперативной памяти) не безразмерный, система вынуждена записывать его на диск. В этом случае файл частично будет записан и частично останется в кэше к моменту закрытия процесса.
← →
Суслик © (2005-04-25 16:12) [9]
> [8] alpet © (25.04.05 16:04)
очень полезная информация.
Разреши поинтересоваться где ты ее взял?
← →
alpet © (2005-04-25 16:18) [10]По словам Рихтера функция TerminateThread - ассинхронная. Так что надеятся на мгновенную смерть потока не стоит. В любом случае стоит почитать оригинал.
Можешь поэкспериментировать с более жестким завершением потока - уничтожением процесса являющимся отладчиком по отношению к исходниму процессу.
В моей практике были случаи когда время завершения потока
доходило до нескольких минут. Но это было следствием странного зависания потока.
← →
mgcr © (2005-04-25 16:18) [11]
> the caching algorithm determines when the buffer is written.
Вот тебе все и сказали.
← →
alpet © (2005-04-25 16:26) [12]> [8] alpet © (25.04.05 16:04)
очень полезная информация.
Разреши поинтересоваться где ты ее взял?
Я в давние времена изучал работу DOS утилиты smartdrv.exe, и насколько понимаю принципы кэширования с тех времен не сильно изменились. Что касается отработки в твоем случае, поток и в самом деле должен умереть практически сразу, засекай время ожидания WaitForSingleObject. Ведь Windows на самом деле нужно АП процесса, которое никуда не девается после завершении "не последнего" потока.
← →
mgcr © (2005-04-25 16:28) [13]
> насколько понимаю принципы кэширования с тех времен не сильно
> изменились
Вообще-то сильно. Советую изучить Руссиновича с Соломоном.
← →
alpet © (2005-04-25 16:33) [14]2 mgcr
Особенно жду. Посылка скоро будет доставлена. Но основной принцип - отложенная запись. На что его можно изменить? Конечно кэширование стало более интеллектуальным, и размер системного кэша теперь изменяется системой realtime. Но как это на высокоуровневой доступ к файлам может повлиять ?
← →
Суслик © (2005-04-25 16:55) [15]
> [11] mgcr © (25.04.05 16:18)
Как раз это противоречит твоим словам...
При close handle никто не сбрасывает кэш.
← →
mgcr © (2005-04-25 17:04) [16]alpet © (25.04.05 16:33) [14]
> Но основной принцип - отложенная запись. На что его можно
> изменить?
Основной принцип - диспетчер кеша не управляет записью. Более того, он даже не знает, какие данные из файлов присутствуют в памяти. Этим всем управляет диспетчер памяти.
← →
alpet © (2005-04-25 17:07) [17]Для принудительной выгрузки буферов надо вызывать FlushFileBuffers. Интересно если попываться завершить поток в момент выполнения функции - система уничтожит его до завершения записи системного кэша? Если в функции осуществляется обработка системного вызова - по идее не должно. Можно сравнить время ожидания WaitForSingleObject (hThread) с FlushFileBuffers и без оного.
← →
alpet © (2005-04-25 17:11) [18]mgcr © (25.04.05 17:04) [16]
Надо будет изучить вопрос. В любом случае выгрузка страниц физической памяти на диск должна выполнятся при ее не хватке.
← →
mgcr © (2005-04-25 17:25) [19]
> If the application does not force the operating system to
> write the buffer to disk before closing the file
Дима, а ты уверен, что файл открывается с отложенной записью ? :)
← →
Суслик © (2005-04-25 17:41) [20]
> [19] mgcr © (25.04.05 17:25)
> If the application does not force the operating system to
>
Игорь, насколько я понимаю не форсить запись файла, является умолчательным поведением. Я не прав? Какой конкретно флаг приводит к отложенной записи?
← →
mgcr © (2005-04-25 17:52) [21]Суслик © (25.04.05 17:41) [20]
Ты бы код записи что ли привел. А то гадаем на кофейной гуще.
← →
Суслик © (2005-04-25 18:13) [22]Господа. Я был неправ. Дома у меня работает несколько иначе чем на работе.
Дома (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.
dfmobject 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
← →
Суслик © (2005-04-25 18:24) [23]Хотел бы еще упомянуть про то, чего я добиваюсь.
С настоящий момент я провожу исследования в области как сохранить большой бинарных файл так, чтобы если в момент записи произойдет выключение питания, то файл либо останется в состоянии до записи, или будет иметь новое содержание.
Собственно вопрос с terminateProcess слабо относится к моей задаче. Я просто исходно по наивности думал, что таким образом смогу смоделировать сбой :))) не вышло :)))
Теперь вопрос про terminateProcess представляет скорее познавательный интерес.
← →
alpet © (2005-04-25 18:30) [24]>> 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
Тогда поток должен поидее завершиться сразу.
← →
mgcr © (2005-04-25 18:31) [25]
> С настоящий момент я провожу исследования в области как
> сохранить большой бинарных файл так, чтобы если в момент
> записи произойдет выключение питания, то файл либо останется
> в состоянии до записи, или будет иметь новое содержание
UPS - рулез фарева. NTFS - рулез фарева. NTFS+UPS двойной рулез.
А зачем надо гонять такие мегабайты туда-сюда, кстати ?
← →
alpet © (2005-04-25 18:33) [26]С настоящий момент я провожу исследования в области как сохранить большой бинарных файл так, чтобы если в момент записи произойдет выключение питания, то файл либо останется в состоянии до записи, или будет иметь новое содержание.
Это проще промоделировать в реальности :=)
Во всяком случае чтобы спровоцировать ошибку в твоем случае, надо попробывать принудительно высвободить страницы памяти из первого потока (VirtualFree), в тот момент когда второй будет пытаться их записывать.
← →
mgcr © (2005-04-25 18:41) [27]
> Собственно вопрос с terminateProcess слабо относится к моей
> задаче. Я просто исходно по наивности думал, что таким образом
> смогу смоделировать сбой :))) не вышло :)))
Кнопка Reset.
Но опять же, извини, не вижу смысла в страдании подобной ерундой. Если ты обмениваешься большими объемами, то средствами файловой системы я полагаю, ты не добьешься поведения "либо полностью старое состояние файла, либо полностью новое". То есть, файловые системы, они, некоторые, транзакционные, но ихние транзакции к пользовательским данным не имеют никакого отношения.
Если очень хочется помучиться, то заведи два файла (небольших, по байту или меньше), перед началом записи большого объема запиши первый файл, означающий "запись данных начата" (и закрой его, сбросив буфер), по успешному окончании записи объема запиши второй файл, означающий "запись данных завершена", а первый удали. Тогда при старте ты будешь знать, в каком состоянии находятся данные твоего большого объема.
Но лучше СУБД использовать - там этот механизм уже успешно реализован.
← →
Суслик © (2005-04-25 18:47) [28]
> [25] mgcr © (25.04.05 18:31)
> А зачем надо гонять такие мегабайты туда-сюда, кстати ?
надо, чтобы программа работала и хранила без всяких сторонних разработок, типа серверов и пр - только файлы. Структура данных чрезвычайно проста - большой бинарный поток. На самом деле он намного меньше - порядка 1-2 мб, просто используя 100мб - легче поймать момент, когда запись не завершена.
Я смотрел fireBird. Мне не равится там ситуация с его поддержкой, и в частности с документированностью. Да и вообще - из пушки по ...
Задача просто - раз в минуту сохранять макс. до 3 мб памяти в один файл. Нужно сделать так, чтогбы ничего не потерялось, т.е. при следующей загрузке:
1. Либо оказался корректный новый файл, при этом информация о сбое отсутстует.
2. Либо оказался корректный старый файл, при этом присутствует информация о сбое.
1
← →
Суслик © (2005-04-25 18:51) [29]
> [27] mgcr © (25.04.05 18:41)
> Если очень хочется помучиться, то заведи два файла (небольших,
> по байту или меньше), перед
Хочу мучаться ерундой, не осуждай уж. Серьезно.
Чем такой вариант хуже?
1. При записи файл данных "a.dat" переименовывается в "a.old"
2. В файл "a.dat" ведется запись новых данных.
3. Происходит сброс данных в файл "a.dat".
4. Файл "a.old" удаляется.
При старте я будут знать дописался ли файл или нет. Если есть old, значит не дописался. Если нет, то значит все ок (т.е. я даже не знаю, про то, что что-то случилось)
← →
alpet © (2005-04-25 19:17) [30]Самая лучшая защита - CRC. В твоем случае не обязательно хэшировать весь файл, но вполне возможно хэшировать его окончание. Если идти твоим путем - можно вести лог-файл в который будут записываться имена файлов успешно записанных на диск, причем запись имен вести через некоторое время (5-10 сек после выполнения FlushFileBuffersEx) что бы была хоть какая-то гарантия, что и аппаратные буфера жесткого диска записались.
← →
Alex Konshin © (2005-04-26 09:47) [31]Ты все 3M перезаписываешь каждый раз?
Почему нельзя писать в другой файл?
Подозреваю, что ты хочешь иметь некую маленькую базу данных.
Могу предложить организовать внутри этого своего файла страничную организацию и изменения всегда писать в другую страницу кроме корневой страницы (твой FAT), которая должна записываться последней. Если размер страницы в файле будет равен размеру сектора (т.е. 512), то как раз и будет гарантироваться транзакциональность изменения. Т.к. 512 байт не достаточно для FAT файла размером 3M, то придется делать его двухуровневым. Т.е. выглядеть должно так:
0-й гиперблок содержит номера блоков, где сидят соответствующие гиперблоки.
Гиперблоки содержат уже номера блоков самого логического файла.
Запись изменений всегда должна происходить в порядке снизу вверх. Т.е. сначала записываешь измененный или новый сектор файла, причем этот сектор обязательно должен быть из списка свободных, ни в коем случае нельзя заменять блок на месте. Потом изменяешь соответствующий гиперблок (пишешь в него номер нового сектора данных) и опять-таки пишешь его на новое место. И, наконец, пишешь корневой гипреблок, в котором изменен номер только что записанного гиперблока, вот его уже пишешь по месту. Весь твой файл нужно открывать без кеширования или, еще лучше, организовать memory mapping.
Собственно, я упрощенно описал принцип работы транзакциональной файловой системы. Те же structured storage работают также. Если сделаешь так, то будет гарантироваться целостность логического файла не зависимо от того, обеспечивает или нет транзакциональность сама файловая система.
← →
Alex Konshin © (2005-04-26 10:01) [32]Какого рода изменения происходят в данных?
Что-то изменяется или только добавляется?
Кстати, очень простую базу в своем файле можно организовать используя то обстоятельство, что можно создавать свои win32 регистри файлы и подключать их к системному регистри. Кстати, надо бы проверить, когда именно происходит изменение состояния регистри, при каждой операции или при закрытии ключа.
То есть, если изменения очень маленькие, то можно использовать регистри как древовидную базу данных. Ну, это, скажете вы, каждый знает. Но не каждый помнит о том, что можно иметь регистри в своем файле.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/regloadkey.asp
← →
Sha © (2005-04-26 10:25) [33]> Alex Konshin © (26.04.05 09:47) [31]
> Весь твой файл нужно открывать без кеширования
> или, еще лучше, организовать memory mapping.
Разве memory mapping гарантирует обновление секторов файла
в порядке обновления секторов в кеше?
← →
Sha © (2005-04-26 10:26) [34]В смысле "страниц в памяти" ?
← →
mgcr © (2005-04-26 10:31) [35]Суслик © (25.04.05 18:51) [29]
Тогда колись дальше: сколько должно быть таких "больших файлов", как они организованы (есть ли ключевые атрибуты и т.д.), как регулярно происходит запись.
От транзакций тебе все равно никуда не деться.
И потом, чем тебе мой или Алекса способ не нравится ?
← →
Sha © (2005-04-26 10:43) [36]> mgcr © (26.04.05 10:31) [35]
> И потом, чем тебе мой или Алекса способ не нравится ?
Тем, что способ [27] не гарантирует надежной работы.
← →
Alex Konshin © (2005-04-26 11:30) [37]Sha © (26.04.05 10:25) [33]
> Alex Konshin © (26.04.05 09:47) [31]
> Весь твой файл нужно открывать без кеширования
> или, еще лучше, организовать memory mapping.
Разве memory mapping гарантирует обновление секторов файла
в порядке обновления секторов в кеше?
Может я и не прав, но мне кажется это решается:
CreateFileMapping
SEC_NOCACHE Sets all pages of a section to non-cashable.
Applications should not use this flag except when explicitly required for a device. Using the interlocked functions with memory mapped by a SEC_NOCACHE section can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.
SEC_NOCACHE requires either the SEC_RESERVE or SEC_COMMIT to be set.
← →
Игорь Шевченко © (2005-04-26 11:52) [38]Sha © (26.04.05 10:43) [36]
> Тем, что способ [27] не гарантирует надежной работы.
Если не секрет, в чем именно ненадежность и в какой ситуации эта ненадежность себя проявит.
← →
Sha © (2005-04-26 11:52) [39]> Alex Konshin © (26.04.05 09:47) [31]
> Потом изменяешь соответствующий гиперблок (пишешь в него номер
> нового сектора данных) и опять-таки пишешь его на новое место.
Кстати, когда делал нечто подобное, чтобы обеспечить возможность
параллельной работы с несколькими файлами в файловой системе,
блоки FAT обновлял сразу по месту и вел отдельно список начал
подвешенных цепочек.
> Alex Konshin © (26.04.05 11:30) [37]
> CreateFileMapping
Как я понял, тут начало важнее, чем конец:All pages of a section are to be set as non-cacheable.
This attribute is intended for architectures requiring various
locking structures to be in memory that is never fetched into
the processor"s. On 80x86 and MIPS machines, using the cache for
these structures only slows down the performance as the hardware
keeps the caches coherent.
Т.е. речь вроде идет о неизменяемых процессором данных.
← →
Sha © (2005-04-26 12:03) [40]> Игорь Шевченко © (26.04.05 11:52) [38]
> Если не секрет, в чем именно ненадежность
> и в какой ситуации эта ненадежность себя проявит.
Файловая система Windows имеет право обновлять данные на диске,
сбрасывая кэш, в произвольной последовательности.
Поэтому при отключении питания мы не можем гарантировать, что данные будут обновлены в обоих файлах. Индикатор может быть выставлен, а данные еще не записаны. При включении питания мы вполне можем обнаружить вместо данных файл нулевой длины.
Страницы: 1 2 3 4 вся ветка
Форум: "WinAPI";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];
Память: 0.58 MB
Время: 0.046 c