Сейчас на форуме: (+2 невидимых)

 eXeL@B —› Оффтоп —› Delphi. Глюки при частом обращении к функе. Помогите найти проблему.
Посл.ответ Сообщение


Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 11 декабря 2009 19:46 · Поправил: ToBad
· Личное сообщение · #1

Столкнулся с проблемой одновременного вывода в лог файл из разных потоков. В силу задачи должен постоянно открывать и закрывать файл при записи строки. Соответственно, что бы не получать I/O error 103 использовал CriticalSection. Эта ошибка пропала, но теперь возникают совершенно другие ошибки и чаще всего инвалид поинтер на goto rt. Ошибка происходит через определённое время, когда сразу, когда через пару минут, для того что бы скорее её узреть сделал 5 потоков и частое обращение. Заметил если в функе xlog закомментировать код после EnterCriticalSection и до result:=s то ошибка не возникает. Так же если оставить одну строку LogFileName:='data_'+DateToStr(now)+'.txt'; - это уже приводит к ошибке. Как я понимаю где то подгаживается стек? Помогите пожалуйста устранить проблему.
Выкладываю код тут и в аттаче с exe вместе.

Code:
  1. Function xlog(lb:byte; pr,s:string):string;
  2. var
  3.   F:TFileStream;
  4.   PStr: PChar;
  5.   LengthLogString: integer;
  6.   LogFileName,LogString:string;
  7. begin
  8.   EnterCriticalSection(logsect);
  9.   LogFileName:='data_'+DateToStr(now)+'.txt';
  10.   if lb>0 then LogString:=pr+' '+TimeToStr(Now) + ': '+inttohex(lb,2)+' '+s+ #13#10 else LogString:=pr+' '+TimeToStr(Now) + ': '+s+ #13#10;
  11.   LengthLogString:= Length(LogString);
  12.   PStr:= StrAlloc(LengthLogString + 1);
  13.   StrPCopy(PStr, LogString);
  14.   if FileExists(LogFileName) then F:=TFileStream.Create(LogFileName, fmOpenWrite) else F:=TFileStream.Create(LogFileName, fmCreate);
  15.   F.Position:= F.Size;
  16.   F.Write(PStr^, LengthLogString);
  17.   StrDispose(PStr);
  18.   F.Free;
  19.   result:=s;
  20.   LeaveCriticalSection(logsect);
  21. end;
  22.  
  23. Function Thr1:dword; StdCall;
  24. Var s:string;
  25. Label rt;
  26. Begin
  27. rt:Sleep(random(10)+1);
  28. s:=xlog(0,'1','1');
  29. goto rt;
  30. Result:=0;
  31. end;
  32.  
  33. Function Thr2:dword; StdCall;
  34. Var s:string;
  35. Label rt;
  36. Begin
  37. rt:Sleep(random(10)+1);
  38. s:=xlog(0,'2','2');
  39. goto rt;
  40. Result:=0;
  41. end;
  42.  
  43. Function Thr3:dword; StdCall;
  44. Var s:string;
  45. Label rt;
  46. Begin
  47. rt:Sleep(random(10)+1);
  48. s:=xlog(0,'3','3');
  49. goto rt;
  50. Result:=0;
  51. end;
  52.  
  53. Function Thr4:dword; StdCall;
  54. Var s:string;
  55. Label rt;
  56. Begin
  57. rt:Sleep(random(10)+1);
  58. s:=xlog(0,'4','4');
  59. goto rt;
  60. Result:=0;
  61. end;
  62.  
  63. Function Thr5:dword; StdCall;
  64. Var s:string;
  65. Label rt;
  66. Begin
  67. rt:Sleep(random(10)+1);
  68. s:=xlog(0,'5','5');
  69. goto rt;
  70. Result:=0;
  71. end;
  72.  
  73. procedure TForm1.Button1Click(Sender: TObject);
  74. begin
  75. Randomize;
  76. InitializeCriticalSection(logsect);
  77. CreateThread(nil,0,@Thr1,nil,0,Dummy);
  78. CreateThread(nil,0,@Thr2,nil,0,Dummy);
  79. CreateThread(nil,0,@Thr3,nil,0,Dummy);
  80. CreateThread(nil,0,@Thr4,nil,0,Dummy);
  81. CreateThread(nil,0,@Thr5,nil,0,Dummy);
  82. end;


02e0_11.12.2009_CRACKLAB.rU.tgz - thrd.rar

p.s. Прошу модератора, если можно, подобрать наиболее подходящий раздел и перенести тему... Тут никто не читает...




Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 11 декабря 2009 22:47 · Поправил: Модератор
· Личное сообщение · #2

Раздел самый подходящий. Ибо форум вообще не для этого, а форумов для дельфи и так пачка.
Да и код абзац, чего стоят только ГОТО, когда есть нормальные циклы while.




Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 11 декабря 2009 23:18
· Личное сообщение · #3

Archer пишет:
Да и код абзац, чего стоят только ГОТО, когда есть нормальные циклы while.


Да, я понимаю, что код некрасивый, но акцентирую внимание не на 5-ти потоках с готом внутри, а на функцию записи в файл, ибо ошибка возникает после её отработки.
Очень хочется услышать замечания по функции xlog которые возможно помогут избежать ошибок...




Ранг: 756.3 (! !), 113thx
Активность: 0.610.05
Статус: Участник
Student

Создано: 11 декабря 2009 23:26 · Поправил: Isaev
· Личное сообщение · #4

ToBad пишет:
на функцию записи в файл, ибо ошибка возникает после её отработки.

в общем вроде относительно корректно написано
долго анализировал и не понял почему может падать
потом качнул, запустил... и правда не падает (15000 записей по крайней мере подождал ~11min)
может от ос зависит? у меня xp sp2

-----
z+Dw7uLu5+jqLCDq7vLu8PvpIPHs7uMh




Ранг: 114.8 (ветеран), 41thx
Активность: 0.10
Статус: Участник

Создано: 12 декабря 2009 01:32
· Личное сообщение · #5

Isaev пишет:
потом качнул, запустил... и правда не падает (15000 записей по крайней мере подождал ~11min)может от ос зависит? у меня xp sp2

У меня наоборот - на sp2 и двух минут нормально не работает). А на sp3 пашет стабильно.




Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 12 декабря 2009 02:30
· Личное сообщение · #6

Странно всё это... У меня на sp3 раньше минуты слетает, а поставил на другой комп на sp2 - пашет уже более часа... И ещё на одном минут 20 тестировали, тоже sp2 и нормально...




Ранг: 756.3 (! !), 113thx
Активность: 0.610.05
Статус: Участник
Student

Создано: 12 декабря 2009 03:21
· Личное сообщение · #7

мда... забавно!
Всё-таки надо значит как-то по другому это реализовать, раз такая нестабильность
и ещё не понятно из-за чего

а когда слетает, лог в каком состоянии?
в смысле свободный/занятый или может на пол строки прерваный

-----
z+Dw7uLu5+jqLCDq7vLu8PvpIPHs7uMh





Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 12 декабря 2009 05:04
· Личное сообщение · #8

Isaev пишет:
а когда слетает, лог в каком состоянии?


Когда как придётся. Когда нормально, а когда так:
Code:
  1. WR 3:55:58: 1
  2. WR 3:55:58: 5
  3. WR и$Щ


А ещё интересно получается, если нажать второй раз - у меня на компе глюкает стабильно, а вот на втором тестовом где без слётов работало до 43Мб лога, потом нажал кнопку 10 раз, а значит общее кол-во потоков 50, дождался до 61 мб и просто прекратил тест. Это 3 часа 40 минут и 4099380 строк в логе без единого глюка.
Какой-то глюкотестер получился...



Ранг: 516.1 (!), 39thx
Активность: 0.280
Статус: Участник

Создано: 12 декабря 2009 15:15
· Личное сообщение · #9

довольно часто стал наблюдать тенденцию, пишешь на дельфи - больше глюков, темы ToBad прямое тому подтверждение, может стоит уже юзать что-нибудь си-подобное?




Ранг: 756.3 (! !), 113thx
Активность: 0.610.05
Статус: Участник
Student

Создано: 12 декабря 2009 18:30
· Личное сообщение · #10

ToBad задай вопрос на delphikingdom возможно там подскажут что путное

-----
z+Dw7uLu5+jqLCDq7vLu8PvpIPHs7uMh





Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 13 декабря 2009 14:39
· Личное сообщение · #11

Av0id - Мои темы - это врядле вина дельфи. Скорее всего я плохой танцор...
Думаю и на Си я не избежал бы подобных тем...

Isaev пишет:
задай вопрос на delphikingdom


Попробую.




Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 19 декабря 2009 19:54
· Личное сообщение · #12

Переделал по-другому, всё равно глючит.... Не пойму что за фигня... Наговорено может???
Подобная конструкция очень часто вылетает с разными ошибками, то инвалид поинтер, то обращение по адресу и память не может быть рид, на другой сборке windows просто молча закрывается. Ошибка происходит через неопределённое время, чаще всего в первые 5 минут работы. Для того, что бы в случае нарушения совместного доступа к файлу лога данные не терялись - реализовал работу со списком. Этот момент работает хорошо. Список не переполняется, ошибка не в этом.

Code:
  1. var
  2.   Form1: TForm1;
  3.   Dummy: dword;
  4.   msgFlag:boolean;
  5.   xlog:TStringList;
  6.  
  7. ...
  8.  
  9. Function LogThread:dword; stdcall;
  10. var
  11.   F:TFileStream;
  12.   PStr: PChar;
  13.   LengthLogString: integer;
  14.   LogFileName,LogString:string;
  15.   fl:boolean;
  16. Label rt,rt2;
  17. Begin
  18. rt:Sleep(300);
  19. rt2:if xlog.Count>0 then begin
  20. sleep(25);
  21.  
  22. fl:=true;
  23. LogFileName:='c:\testlog.txt';
  24. LogString:=xlog.Strings[0]+#13#10;
  25.   LengthLogString:= Length(LogString);
  26.   PStr:= StrAlloc(LengthLogString + 1);
  27.   StrPCopy(PStr, LogString);
  28.   try
  29.   if FileExists(LogFileName) then F:=TFileStream.Create(LogFileName, fmOpenWrite) else F:=TFileStream.Create(LogFileName, fmCreate);
  30.   F.Position := F.Size;
  31.   F.Write(PStr^, LengthLogString);
  32.   F.Free;
  33.   except
  34.   fl:=not fl;
  35.   end;
  36.   StrDispose(PStr);
  37.   if fl then xlog.Delete(0) else goto rt;
  38.   goto rt2;
  39. end;
  40. goto rt;
  41. Result:=0;
  42. end;
  43.  
  44. Function Thr1:dword; StdCall;
  45. Begin
  46. while msgFlag do begin
  47. Sleep(random(100)+50);
  48. xlog.Add('test1');
  49. end;
  50. Result:=0;
  51. end;
  52.  
  53. Function Thr2:dword; StdCall;
  54. Begin
  55. while msgFlag do begin
  56. Sleep(random(100)+50);
  57. xlog.Add('test2');
  58. end;
  59. Result:=0;
  60. end;
  61.  
  62. procedure TForm1.Button1Click(Sender: TObject);
  63. begin
  64. Randomize;
  65. msgFlag:=true;
  66. xlog:=TStringList.Create;
  67. CreateThread(nil,0,@LogThread,nil,0,Dummy);
  68. CreateThread(nil,0,@Thr1,nil,0,Dummy);
  69. CreateThread(nil,0,@Thr2,nil,0,Dummy);
  70. end;


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

c7dd_19.12.2009_CRACKLAB.rU.tgz - thrd_test_prj.exe



Ранг: 516.1 (!), 39thx
Активность: 0.280
Статус: Участник

Создано: 19 декабря 2009 20:07
· Личное сообщение · #13

попробуй синхронизировать потоки через CreateEvent, в msdn'е прекрасный пример есть

msdn.microsoft.com/en-us/library/ms686915%28VS.85%29.aspx



Ранг: 309.8 (мудрец), 21thx
Активность: 0.170
Статус: Участник

Создано: 20 декабря 2009 07:04
· Личное сообщение · #14

Всё не читал, но если нужна синхронизация с логер тредом быстрее и лучше в данном случае использовать критические секции со спином.

-----
Shalom ebanats!





Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 27 апреля 2010 00:21
· Личное сообщение · #15

Всё было банально, не хватало этого: System.IsMultiThread:=true;



Ранг: 172.2 (ветеран)
Активность: 0.070
Статус: Участник

Создано: 15 мая 2010 11:39
· Личное сообщение · #16

была схожая проблема в малтритредед делфовом же приложении, падения потоков были всегда "в окресностях" кода работы с данными типа string

-----
HOW MUCH BLOOD WOULD YOU SHED TO STAY ALIVE





Ранг: 450.3 (мудрец), 13thx
Активность: 0.20
Статус: Участник

Создано: 18 мая 2010 18:36
· Личное сообщение · #17

ProTeuS пишет:
падения потоков были всегда "в окресностях" кода работы с данными типа string


Да, да, именно там и у меня...


 eXeL@B —› Оффтоп —› Delphi. Глюки при частом обращении к функе. Помогите найти проблему.

У вас должно быть 20 пунктов ранга, чтобы оставлять сообщения в этом подфоруме, но у вас только 0

   Для печати Для печати