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

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

Нити и запись в индивидуальный файл.


Страницы:   1 2

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,...);

Переменная одна, потоков много. Теоретически один может открыть файл, потом сразу же второй, со всеми вытекающими.


Страницы:   1 2

Наверх

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