Текущий архив: 2007.05.13;
Скачать: CL | DM;
Вниз
Нити и запись в индивидуальный файл. Найти похожие ветки
← →
Riply © (2007-04-19 18:46) [0]Здравствуйте !
Есть много нитей (в одном процессе), каждая из них (как только ей захочеться :),
может вызвать следущую процедуру, для записи в личный файл:procedure Test_CallBack(cbError: DWord; BytesTransf: DWord); stdcall;
var
FileName: string;
begin
FileName := TestDir + PathDelim + IntToStr(GetCurrentThreadID) + ".txt";
if not Str_AddToFile(FileName, IntToStr(cbError) + "=" + IntToStr(BytesTransf))
then Log_WriteError("Error on: Test_CallBack - Str_AddToFile", GetLastError);
end;
Где
Str_AddToFile(const FName, StrValue: string) - Просто добавляет строку в файл(FName). Ничем не защищена.
Log_WriteError - Пишет в общий лог. Защищена глобальной кр. секцией.
Иногда запись в файл (Str_AddToFile) не происходит.
Возвращаемая ошибка: "The process cannot access the file because it is being used by another process".
Совсем перестала соображать: никак не получается представить себе ситуацию, когда это возможно.
Подскажите, пожалуйста, почему так происходит ?
← →
Kolan © (2007-04-19 18:51) [1]> Str_AddToFile(const FName, StrValue: string) — Просто добавляет
> строку в файл(FName). Ничем не защищена.
> Log_WriteError — Пишет в общий лог. Защищена глобальной
> кр. секцией.
Главное сами пишете, что одно зашишино крит. секцией а второе нет… А потом спрашиваете «почему так происходит ?»
— Странно
ЗЫ
Смешивать стьль оформления Си и Delphi — фу… :)
← →
umbra © (2007-04-19 18:55) [2]
> Есть много нитей (в одном процессе), каждая из них (как
> только ей захочеться :),
> может вызвать следущую процедуру, для записи в личный файл
предыдущее обращение к файлу не закончилось.
← →
Riply © (2007-04-19 18:55) [3]> [1] Kolan © (19.04.07 18:51)
>Главное сами пишете, что одно зашишино крит. секцией а второе нет…
>А потом спрашиваете «почему так происходит ?»
Ну и что ?
Мне непонятно, в чем крамола ?
Можете "на пальцах" объяснить что здесь "не так" ?
← →
Riply © (2007-04-19 18:57) [4]> [2] umbra © (19.04.07 18:55)
>предыдущее обращение к файлу не закончилось.
"не закончилось" в той же нити ? или в другой ?
Если в другой, то мы и открываем другой файл.
← →
Kolan © (2007-04-19 18:59) [5]> Можете «на пальцах» объяснить что здесь «не так»
Вот вы зачем лог защитили, а?
И чем «лог» файл отличается от другого файла? Уверен что ничем…
← →
Kolan © (2007-04-19 19:00) [6]> Если в другой, то мы и открываем другой файл.
Тогда код показывайте, так ниче не понятно.
← →
Riply © (2007-04-19 19:03) [7]> [5] Kolan © (19.04.07 18:59)
>Вот вы зачем лог защитили, а?
Причем здесь это ?
Функцию записи в лог(которая, кстати, срабатывает только после ошибки в предыдущей),
можно вообще убрать.
Я не могу понять, почему не всегда срабатывает первая.
← →
Riply © (2007-04-19 19:04) [8]> [6] Kolan © (19.04.07 19:00)
>Тогда код показывайте, так ниче не понятно.
>[0] Riply © (19.04.07 18:46)
>FileName := TestDir + PathDelim + IntToStr(GetCurrentThreadID) + ".txt";
← →
Kolan © (2007-04-19 19:08) [9]> Str_AddToFile
Это вот что делает? Те как конкретно записывается в файл, что за файл…
> Я не могу понять, почему не всегда срабатывает первая.
Как это не можете, сами же пишете «The process cannot access the file because it is being used by another process», вопрос почему так получается как я понял…
← →
Leonid Troyanovsky © (2007-04-19 19:08) [10]
> Riply © (19.04.07 18:46)
> Подскажите, пожалуйста, почему так происходит ?
Как создавались эти потоки (threads)?
--
Regards, LVT.
← →
Riply © (2007-04-19 19:17) [11]> [10] Leonid Troyanovsky © (19.04.07 19:08)
>Как создавались эти потоки (threads)?
QueueUserWorkItem и BindIoCompletionCallback
← →
Riply © (2007-04-19 19:19) [12]> [11] Riply © (19.04.07 19:17)
Test_CallBack находиться внутри их(QueueUserWorkItem и BindIoCompletionCallback) колбэков.
← →
Leonid Troyanovsky © (2007-04-19 19:25) [13]
> Riply © (19.04.07 19:17) [11]
> QueueUserWorkItem и BindIoCompletionCallback
System.IsMultithread := True?
--
Regards, LVT.
← →
umbra © (2007-04-19 19:27) [14]а разве IoCompletion - это синхронная запись?
← →
Riply © (2007-04-19 19:27) [15]> [13] Leonid Troyanovsky © (19.04.07 19:25)
>System.IsMultithread := True?
Вручную не ставила.
← →
Riply © (2007-04-19 19:30) [16]P.S.
Пойду проверять с IsMultithread := True.
Займет некоторое время. Ошибка редко проявляется :(
← →
Riply © (2007-04-19 19:40) [17]>[11] Riply © (19.04.07 19:17)
Забыла добавить. Еще используются ReadFileEx и WriteFileEx (c OVERLAPPED_COMPLETION_ROUTINE).
Просто пока тестирую, сервер и клиенты сидят в одном процессе.
← →
Riply © (2007-04-19 19:42) [18]Тороплюсь. Не добавила: в них Test_CallBack, тоже вызывается
← →
Sapersky (2007-04-19 19:48) [19]Может, файл действительно is being used by another process, например, открыт каким-нибудь просмотрщиком, который запрещает его изменять?
Пойду проверять с IsMultithread := True.
Вряд ли только это. Str_AddToFile ведь не системная функция? Видимо, там что-то вроде:
Var h : THandle;
h := CreateFile(...);
или
Var f : TextFile;
AssignFile(f,...);
Переменная одна, потоков много. Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.
← →
Leonid Troyanovsky © (2007-04-19 19:54) [20]
> Riply © (19.04.07 19:42) [18]
> Тороплюсь. Не добавила: в них Test_CallBack, тоже вызывается
Во-ще-то, лучше было завести мап открытых потоками файлов,
т.е. tid -> THandle, а не обращаться к ним по имени.
--
Regards, LVT.
ЗЫ Т.е., если IsMultithread не устанавливался (не вызывался BeginThread)
то проблема именно здесь, в операциях со String.
← →
Riply © (2007-04-19 19:56) [21]> [19] Sapersky (19.04.07 19:48)
>Может, файл действительно is being used by another process, например, открыт каким-нибудь просмотрщиком, >который запрещает его изменять?
:) Нет, конечно.
>>Пойду проверять с IsMultithread := True.
>Вряд ли только это.
Даю Не это. IsMultithread исходно была True.
>Str_AddToFile ведь не системная функция? Видимо, там что-то вроде:
>Var h : THandle;
>h := CreateFile(...);
Именно такая
>Переменная одна, потоков много.
>Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.
Как-то мне не удается представить себе такую ситуацию :(
← →
Riply © (2007-04-19 20:02) [22]> [20] Leonid Troyanovsky © (19.04.07 19:54)
>ЗЫ Т.е., если IsMultithread не устанавливался (не вызывался BeginThread)
>то проблема именно здесь, в операциях со String.
BeginThread в одном месте вызывается, но раньше начала "пулл - вызовов" или позже - непредсказуемо.
Когда работа заканчивается IsMultithread - True
>Во-ще-то, лучше было завести мап открытых потоками файлов,
>т.е. tid -> THandle, а не обращаться к ним по имени.
Наверное так и сделаю.
← →
Leonid Troyanovsky © (2007-04-19 20:37) [23]
> Riply © (19.04.07 20:02) [22]
> Когда работа заканчивается IsMultithread - True
Гораздо интересней его состояние в момент ошибки.
Видимо, тебе ждет подготовка минимального проекта,
воспроизводящиего ошибку ;)
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-19 20:44) [24]
> Riply © (19.04.07 20:02) [22]
> >т.е. tid -> THandle, а не обращаться к ним по имени.
> Наверное так и сделаю.
Я бы, вообще, попробывал работать в потоках и без IsMultithread = true,
т.е., без стрингов, вариантов и т.п., а только с PChar, PWChar & etc.
--
Regards, LVT.
← →
Sapersky (2007-04-19 20:49) [25]>Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.
Как-то мне не удается представить себе такую ситуацию :(
Точно, не может быть её - забыл, что стеки у потоков разные.
← →
Riply © (2007-04-19 21:39) [26]> [23] Leonid Troyanovsky © (19.04.07 20:37)
>Гораздо интересней его состояние в момент ошибки.
Прогоняла все в "жестком режиме". Удалось дождаться ошибки.
Перед первым "пуловым" вызовом и сразу после него (у меня это BindIoCompletionCallback)
IsMultiThread - False. (и почему это она не устанавливает его в True ?).
На момент ошибки IsMultiThread - True.
Ошибка происходит при вызове CreateFile(PChar(FName), GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0);
Еще интересный момент: после появления этой ошибки
(если не перезапускать проект) она больше не появляется. Все работает как часы. Ждала довольно долго.
Если же перезапустить проект, то ее можно дождаться за пять - десять минут.
С установкой вручную IsMultiThread в True еще не пробовала.
>Видимо, тебе ждет подготовка минимального проекта,
>воспроизводящиего ошибку ;)
Ну нельзя же так пугать людей !
У них может оказаться слабое сердце :)
← →
Riply © (2007-04-19 21:50) [27]>[24] Leonid Troyanovsky © (19.04.07 20:44)
>Я бы, вообще, попробывал работать в потоках и без IsMultithread = true,
>т.е., без стрингов, вариантов и т.п., а только с PChar, PWChar & etc.
И с чего лучше начать тестировать ?
С перехода на PChar"ы (у меня во многих местах используются стринги) или с IsMultithread:= True ?
И почему Multithread плохо уживается со стрингами ?
← →
Kolan © (2007-04-19 22:35) [28]Cтрано, как это вы не зная точно что в этом «Str_AddToFile» обсуждаете. :(
Наверно телепатор у меня совсем хреновый :(…
← →
Leonid Troyanovsky © (2007-04-19 23:10) [29]
> iply © (19.04.07 21:50) [27]
> И почему Multithread плохо уживается со стрингами ?
Во многом благодаря дельфийскому менеджеру памяти.
Т.е., если не предпринять определенных усилий, то
станет непредсказуемым даже перераспределение строки,
бо, только в режиме IsMultithread = true, память
перераспределяют с учетом конкурентов, т.е. через
критическую секцию.
--
Regards, LVT.
← →
Riply © (2007-04-19 23:35) [30]> [29] Leonid Troyanovsky © (19.04.07 23:10)
Спасибо большое !
Принудительная установка Multithread"а помогла. Добиться возникновеня ошибки не удается :)
>Т.е., если не предпринять определенных усилий, то
>станет непредсказуемым даже перераспределение строки,
Придется переходить на PChar"ы. :)
← →
Riply © (2007-04-19 23:38) [31]>[28] Kolan © (19.04.07 22:35)
>Cтрано, как это вы не зная точно что в этом «Str_AddToFile» обсуждаете. :(
>Наверно телепатор у меня совсем хреновый :(
Нормальный :)
Там, кроме записи строки в конец файла ничего нет :)
← →
Kolan © (2007-04-19 23:41) [32]> Там, кроме записи строки в конец файла ничего нет :)
Ну ладно,
> Добиться возникновеня ошибки не удается :)
и слава богу.
← →
SlymRO © (2007-04-20 06:39) [33]Riply © (19.04.07 23:35) [30]
Придется переходить на PChar"ы. :)
Выделяемые через GetMem? тот же менеджер памяти что и при string => теже грабли, но возможно реже...
← →
Leonid Troyanovsky © (2007-04-20 09:19) [34]
> SlymRO © (20.04.07 06:39) [33]
>> Придется переходить на PChar"ы. :)
> Выделяемые через GetMem? тот же менеджер памяти что и при
> string => теже грабли, но возможно реже...
Можно выделить достаточно большой блок в первичном потоке,
и разделить его на буферы для каждого потока.
На худой конец, каждый поток может сделать VirtualAlloc-VirtualFree.
--
Regards, LVT.
← →
Riply © (2007-04-20 11:30) [35]> [34] Leonid Troyanovsky © (20.04.07 09:19)
>Можно выделить достаточно большой блок в первичном потоке,
>и разделить его на буферы для каждого потока.
Честно говоря, я плохо представляю даже скелет такой конструкциии.
У меня создается "популяция" нитей, контролировать которую я, парктически не в состоянии.
Нити в ней живут собственной жизнью и по собственным правилам.
Рождаются, что-то делают, умирают.
Их кол-во в данный момент времени зависит от "норова" пула и расположения звезд.
Если, я правильно понимаю, то нелзя даже утановить взаимосвязь "клиент - нить"
Т. к. возможны такие ситуации, когда "клиента" начинает обслуживать одна нить,
а продолжит другая. И, наоборот, за свою жизнь одна нить может успеть
поработать не только не одного клиента.
← →
SlymRO © (2007-04-20 12:11) [36]Riply © (20.04.07 11:30) [35]
Т. к. возможны такие ситуации, когда "клиента" начинает обслуживать одна нить,
а продолжит другая. И, наоборот, за свою жизнь одна нить может успеть
поработать не только не одного клиента.
С пулами именно так...
Leonid Troyanovsky © (20.04.07 9:19) [34]
и разделить его на буферы для каждого потока
А менеджер памяти не так делает?
← →
Leonid Troyanovsky © (2007-04-20 14:00) [37]
> Riply © (20.04.07 11:30) [35]
> >и разделить его на буферы для каждого потока.
> Честно говоря, я плохо представляю даже скелет такой конструкциии.
Ну, мне тоже трудно сконструировать что-то,
если детали мне неизвестны.
Например, потоки нуждаются в буфере для строк.
Сделаем (в первичном потоке) двумерный массив Char для хранения
строк фиксированной длины. Занятость строк определим с помощью
TBits, доступ к которому должен быть защищен критической секцией.
Т.е., заинтересованный поток получает у TBits индекс свободной
строки, устанавливает бит, работает со строкой, а при освобождении сбрасывает бит.
Если обработка ведется разными потоками, то список занятых строк
хранится в некоторой управляющей структуре, связанной
с заданием, обрабатываемым пулом.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2007-04-20 14:03) [38]
> SlymRO © (20.04.07 12:11) [36]
> и разделить его на буферы для каждого потока
> А менеджер памяти не так делает?
Так. Я ж говорил про первичный поток, т.е.,
он распределяет (освобождает).
Остальные только пользуются.
--
Regards, LVT.
Страницы: 1 вся ветка
Текущий архив: 2007.05.13;
Скачать: CL | DM;
Память: 0.58 MB
Время: 0.054 c