![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Нити и запись в индивидуальный файл.
Riply © (2007-04-19 18:46:00)Здравствуйте !
Есть много нитей (в одном процессе), каждая из них (как только ей захочеться :),
может вызвать следущую процедуру, для записи в личный файл:
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".
Совсем перестала соображать: никак не получается представить себе ситуацию, когда это возможно.
Подскажите, пожалуйста, почему так происходит ?
Leonid Troyanovsky (2007-04-20 14:03:00) [1]
> SlymRO © (20.04.07 12:11) [36]
> и разделить его на буферы для каждого потока
> А менеджер памяти не так делает?
Так. Я ж говорил про первичный поток, т.е.,
он распределяет (освобождает).
Остальные только пользуются.
--
Regards, LVT.
Leonid Troyanovsky (2007-04-20 14:00:00) [2]
> Riply © (20.04.07 11:30) [35]
> >и разделить его на буферы для каждого потока.
> Честно говоря, я плохо представляю даже скелет такой конструкциии.
Ну, мне тоже трудно сконструировать что-то,
если детали мне неизвестны.
Например, потоки нуждаются в буфере для строк.
Сделаем (в первичном потоке) двумерный массив Char для хранения
строк фиксированной длины. Занятость строк определим с помощью
TBits, доступ к которому должен быть защищен критической секцией.
Т.е., заинтересованный поток получает у TBits индекс свободной
строки, устанавливает бит, работает со строкой, а при освобождении сбрасывает бит.
Если обработка ведется разными потоками, то список занятых строк
хранится в некоторой управляющей структуре, связанной
с заданием, обрабатываемым пулом.
--
Regards, LVT.
SlymRO (2007-04-20 12:11:00) [3]Riply © (20.04.07 11:30) [35]
Т. к. возможны такие ситуации, когда "клиента" начинает обслуживать одна нить,
а продолжит другая. И, наоборот, за свою жизнь одна нить может успеть
поработать не только не одного клиента.
С пулами именно так...
Leonid Troyanovsky © (20.04.07 9:19) [34]
и разделить его на буферы для каждого потока
А менеджер памяти не так делает?
Riply (2007-04-20 11:30:00) [4]> [34] Leonid Troyanovsky © (20.04.07 09:19)
>Можно выделить достаточно большой блок в первичном потоке,
>и разделить его на буферы для каждого потока.
Честно говоря, я плохо представляю даже скелет такой конструкциии.
У меня создается "популяция" нитей, контролировать которую я, парктически не в состоянии.
Нити в ней живут собственной жизнью и по собственным правилам.
Рождаются, что-то делают, умирают.
Их кол-во в данный момент времени зависит от "норова" пула и расположения звезд.
Если, я правильно понимаю, то нелзя даже утановить взаимосвязь "клиент - нить"
Т. к. возможны такие ситуации, когда "клиента" начинает обслуживать одна нить,
а продолжит другая. И, наоборот, за свою жизнь одна нить может успеть
поработать не только не одного клиента.
Leonid Troyanovsky (2007-04-20 09:19:00) [5]
> SlymRO © (20.04.07 06:39) [33]
>> Придется переходить на PChar'ы. :)
> Выделяемые через GetMem? тот же менеджер памяти что и при
> string => теже грабли, но возможно реже...
Можно выделить достаточно большой блок в первичном потоке,
и разделить его на буферы для каждого потока.
На худой конец, каждый поток может сделать VirtualAlloc-VirtualFree.
--
Regards, LVT.
SlymRO (2007-04-20 06:39:00) [6]Riply © (19.04.07 23:35) [30]
Придется переходить на PChar'ы. :)
Выделяемые через GetMem? тот же менеджер памяти что и при string => теже грабли, но возможно реже...
Kolan (2007-04-19 23:41:00) [7]> Там, кроме записи строки в конец файла ничего нет :)
Ну ладно,
> Добиться возникновеня ошибки не удается :)
и слава богу.
Riply (2007-04-19 23:38:00) [8]>[28] Kolan © (19.04.07 22:35)
>Cтрано, как это вы не зная точно что в этом «Str_AddToFile» обсуждаете. :(
>Наверно телепатор у меня совсем хреновый :(
Нормальный :)
Там, кроме записи строки в конец файла ничего нет :)
Riply (2007-04-19 23:35:00) [9]> [29] Leonid Troyanovsky © (19.04.07 23:10)
Спасибо большое !
Принудительная установка Multithread'а помогла. Добиться возникновеня ошибки не удается :)
>Т.е., если не предпринять определенных усилий, то
>станет непредсказуемым даже перераспределение строки,
Придется переходить на PChar'ы. :)
Leonid Troyanovsky (2007-04-19 23:10:00) [10]
> iply © (19.04.07 21:50) [27]
> И почему Multithread плохо уживается со стрингами ?
Во многом благодаря дельфийскому менеджеру памяти.
Т.е., если не предпринять определенных усилий, то
станет непредсказуемым даже перераспределение строки,
бо, только в режиме IsMultithread = true, память
перераспределяют с учетом конкурентов, т.е. через
критическую секцию.
--
Regards, LVT.
Kolan (2007-04-19 22:35:00) [11]Cтрано, как это вы не зная точно что в этом «Str_AddToFile» обсуждаете. :(
Наверно телепатор у меня совсем хреновый :(
Riply (2007-04-19 21:50:00) [12]>[24] Leonid Troyanovsky © (19.04.07 20:44)
>Я бы, вообще, попробывал работать в потоках и без IsMultithread = true,
>т.е., без стрингов, вариантов и т.п., а только с PChar, PWChar & etc.
И с чего лучше начать тестировать ?
С перехода на PChar'ы (у меня во многих местах используются стринги) или с IsMultithread:= True ?
И почему Multithread плохо уживается со стрингами ?
Riply (2007-04-19 21:39:00) [13]> [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 еще не пробовала.
>Видимо, тебе ждет подготовка минимального проекта,
>воспроизводящиего ошибку ;)
Ну нельзя же так пугать людей !
У них может оказаться слабое сердце :)
Sapersky (2007-04-19 20:49:00) [14]>Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.
Как-то мне не удается представить себе такую ситуацию :(
Точно, не может быть её - забыл, что стеки у потоков разные.
Leonid Troyanovsky (2007-04-19 20:44:00) [15]
> Riply © (19.04.07 20:02) [22]
> >т.е. tid -> THandle, а не обращаться к ним по имени.
> Наверное так и сделаю.
Я бы, вообще, попробывал работать в потоках и без IsMultithread = true,
т.е., без стрингов, вариантов и т.п., а только с PChar, PWChar & etc.
--
Regards, LVT.
Leonid Troyanovsky (2007-04-19 20:37:00) [16]
> Riply © (19.04.07 20:02) [22]
> Когда работа заканчивается IsMultithread - True
Гораздо интересней его состояние в момент ошибки.
Видимо, тебе ждет подготовка минимального проекта,
воспроизводящиего ошибку ;)
--
Regards, LVT.
Riply (2007-04-19 20:02:00) [17]> [20] Leonid Troyanovsky © (19.04.07 19:54)
>ЗЫ Т.е., если IsMultithread не устанавливался (не вызывался BeginThread)
>то проблема именно здесь, в операциях со String.
BeginThread в одном месте вызывается, но раньше начала "пулл - вызовов" или позже - непредсказуемо.
Когда работа заканчивается IsMultithread - True
>Во-ще-то, лучше было завести мап открытых потоками файлов,
>т.е. tid -> THandle, а не обращаться к ним по имени.
Наверное так и сделаю.
Riply (2007-04-19 19:56:00) [18]> [19] Sapersky (19.04.07 19:48)
>Может, файл действительно is being used by another process, например, открыт каким-нибудь просмотрщиком, >который запрещает его изменять?
:) Нет, конечно.
>>Пойду проверять с IsMultithread := True.
>Вряд ли только это.
Даю Не это. IsMultithread исходно была True.
>Str_AddToFile ведь не системная функция? Видимо, там что-то вроде:
>Var h : THandle;
>h := CreateFile(...);
Именно такая
>Переменная одна, потоков много.
>Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.
Как-то мне не удается представить себе такую ситуацию :(
Leonid Troyanovsky (2007-04-19 19:54:00) [19]
> Riply © (19.04.07 19:42) [18]
> Тороплюсь. Не добавила: в них Test_CallBack, тоже вызывается
Во-ще-то, лучше было завести мап открытых потоками файлов,
т.е. tid -> THandle, а не обращаться к ним по имени.
--
Regards, LVT.
ЗЫ Т.е., если IsMultithread не устанавливался (не вызывался BeginThread)
то проблема именно здесь, в операциях со String.
Sapersky (2007-04-19 19:48:00) [20]Может, файл действительно is being used by another process, например, открыт каким-нибудь просмотрщиком, который запрещает его изменять?
Пойду проверять с IsMultithread := True.
Вряд ли только это. Str_AddToFile ведь не системная функция? Видимо, там что-то вроде:
Var h : THandle;
h := CreateFile(...);
или
Var f : TextFile;
AssignFile(f,...);
Переменная одна, потоков много. Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.