Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   API de Windows (https://www.clubdelphi.com/foros/forumdisplay.php?f=7)
-   -   WaitForSingleObject se queda bloqueada (https://www.clubdelphi.com/foros/showthread.php?t=54272)

seoane 12-03-2008 23:10:31

WaitForSingleObject se queda bloqueada
 
1 Archivos Adjunto(s)
Tengo una pequeña funcion para guardar mensajes de log en un archivo (la misma que publique en la seccion de trucos). La funcion funciona muy bien, y nunca me habia dado problemas hasta ahora :(

El problema aparece cuando se crean varios threads y desde todos ellos se llama a la funcion. Al principio parece que aguanta bien, ya la he usado en varios programas con threads sin problemas, pero cuando se hace un uso muy intensivo de la misma a veces falla. Cuando falla, la funcion WaitForSingleObject se queda esperando indefinidamente, bloqueando asi el thread que llamo la funcion.

El codigo es el siguiente (abajo pongo un ejemplo en un zip)
Código Delphi [-]
unit ULog;

interface

uses Windows, Sysutils, dialogs;  

procedure log(Archivo, Mensaje: String); overload;
procedure log(Mensaje: String); overload;

implementation

var
  LogFile: String;
  Mutex: THandle;

procedure log(Archivo, Mensaje: String); overload;
var
  F: TextFile;
  SearchRec: TSearchRec;
  Str: String;
begin
  if Mutex <> 0 then
  begin
    // Aqui esta el problema
    WaitForSingleObject(Mutex, INFINITE);
    try
      if FindFirst(Archivo,faAnyFile,SearchRec) = 0 then
      begin
        if SearchRec.Size > (1024*1024) then
        begin
          Str:= IncludeTrailingPathDelimiter(ExtractFilePath(Archivo))
            + 'Historico\';
          ForceDirectories(Str);
          MoveFileEx(PChar(Archivo),PChar(Str + FormatDateTime('yyyymmdd',Now)
            + '.log'), MOVEFILE_REPLACE_EXISTING);
        end;
        FindClose(SearchRec);
      end;
      try
        AssignFile(F, Archivo);
        {$I-}
          Append(F);
        if IOResult <> 0 then
          Rewrite(F);
        {$I+}
        if IOResult = 0 then
        begin
          Writeln(F,Mensaje);
          CloseFile(F);
        end;
      except
        //
      end;
    finally
      // Aqui me aseguro de liberar el mutex
      ReleaseMutex(Mutex);
    end;
  end;
end;

procedure log(Mensaje: String); overload;
begin
  try
    Mensaje:= FormatDateTime('[ddd dd mmm, hh:nn] ', Now) + Mensaje;
    log(LogFile,Mensaje);
  except
    //
  end;
end;

initialization
  LogFile:= ChangeFileExt(ParamStr(0),'.log');
  Mutex:= CreateMutex(nil,TRUE,
    PChar(StringReplace(LogFile,'\','/',[rfReplaceAll])));
finalization
  CloseHandle(Mutex);
end.

Y para probar la funcion utilizo el siguiente codigo:
Código Delphi [-]
program logtest;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  Messages,
  Classes,
  ULog in 'ULog.pas';

type
  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  ThreadCount: Integer;

{ TTestThread }
procedure TTestThread.Execute;
var
  i: Integer;
begin
  InterlockedIncrement(ThreadCount);
  for i:= 0 to 10 do
  begin
    log(Format('[%d] %d',[Handle,i]));
    Sleep(10);
  end;
  InterlockedDecrement(ThreadCount);
end;

var
  j,k: Integer;
begin
  j:= 0;
  ThreadCount:= 0;
  while TRUE do
  begin
    // Si no hay threads lanzo 5
    if ThreadCount = 0 then
    begin
      for k:= 1 to 5 do
      begin
        inc(j);
        Writeln(Format('Creado un nuevo Thread: %d',[j]));
        TTestThread.Create(FALSE).FreeOnTerminate:= TRUE;
      end;
    end else;
      Sleep(10);
  end; 
end.

No se que puede estar fallando, hasta utilizo un bloque "try ... finally" para asegurarme de que se libera el mutex, pero aun asi nada :confused:

¿Alguien puede ver lo que se me escapa? El problema se podria solucionar cambiando el parametro INFINITE por un tiempo mas pequeño, pero ademas de que eso seria una chapuza, se perderian mensajes.

seoane 12-03-2008 23:25:17

Ya me respondo yo :D , el problema estaba aquí:
Código Delphi [-]
  Mutex:= CreateMutex(nil,TRUE,
    PChar(StringReplace(LogFile,'\','/',[rfReplaceAll])));

Me estaba apropiando del mutex al crearlo y no lo estaba liberando :(

Solución:
Código Delphi [-]
Mutex:= CreateMutex(nil,FALSE,
    PChar(StringReplace(LogFile,'\','/',[rfReplaceAll])));

Llevo varios días dándole vueltas y hasta que lo publique no me dí cuenta de ese detalle. :D

dec 12-03-2008 23:45:09

Hola,

Probando el programa de ejemplo que has puesto, ¿cuándo se supone que falla? Supongo que cuando se crean cinco hilos (generalmente) y no se continua adelante. ¿Es así? Puesto que si abres varias instancias del programa y, cierras alguna, no siempre, pero, a veces los hilos comienzan a crearse "sin límite", que es lo que se supone que tiene que pasar siempre, si no me equivoco.

Lamento no saber decir Domingo, sólo tenía esas dudas, por un lado, y, por otro, quizás algo extraño, y es que, si en lugar de "INIFINITE", como has dicho, lo cambio por algunos milisegundos, el programa se comporta igual, y, esto me confunde, porque antes dijiste que con eso podría solucionarse, pero, que, era una chapuza. Sea o no una chapuza (que si tú lo dices será así) digo que el programa se comporta igual en mi caso.

Windows XP SP2
Delphi 2007 for Win32

Edito: Ya vi que encontraste la solución. ;) También la probé y funciona bien todo. Pues nada, eres más rápido tú en preguntar y solucionar que yo en tratar de decir esta boca es mía nada más... :D :D :D

seoane 12-03-2008 23:59:14

Pues ya ves dec, un simple TRUE casi me vuelve loco :D

Lo que quedo claro es que escribir en el foro es toda una catarsis :D :D :D


La franja horaria es GMT +2. Ahora son las 08:34:18.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi