Q&A

  • Thread에서 Access violation 에러..
안녕하세요.. Thread를 공부해볼려고 나름의 예제를 만들어서 계획중인데요.

이상하게 Access Violation 에러가 나네요.

그것도 불규칙적으로요.. 도저히 원인을 찾을수가 없어서 이렇게 문의 드립니다.

밑에 보시면 중간에 DataPrint 프로시져에서 루프를 돌리는 부분에서 에러가 납니다.

이 예제는 루프 10000번을 돌릴 동안에 다른 버튼을 누르면 "멈춰"라는 메세지를 띄우는 예제인데요...

잘 돌아가다가 중간중간 오류가 나더라구요.. 도대체 왜 그럴까요??

도와주세요~~


<!--CodeS-->

unit Form;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls, Buttons;

type
  TFrmTest = class(TForm)
    Button: TButton;
    StringGrid: TStringGrid;
    BitBtn1: TBitBtn;
    Edit1: TEdit;
    Label1: TLabel;
    procedure ButtonClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
  private
    GridThread, BtnThread : TThread;
    procedure DataPrint;
    { Private declarations }
  public
    { Public declarations }

  end;

var
  FrmTest: TFrmTest;

implementation

{$R *.dfm}

  Type
    TGridThread = Class(TThread)

    private
      procedure CellPrint;
    protected
      procedure Execute; Override;
    end;

{ TGridThread }

procedure TGridThread.CellPrint;
begin
  FrmTest.DataPrint;
end;


procedure TGridThread.Execute;
begin
   CellPrint;
end;

  type TButtonThread = Class(TThread)
    private
      procedure ButtonStop;
    protected
      procedure Execute; Override;

  end;

procedure TFrmTest.ButtonClick(Sender: TObject);
begin
  if Assigned(GridThread) then
  begin
    GridThread.Free;
    GridThread := Nil;
  end;

  GridThread := TGridThread.Create(False);

  with GridThread do
  begin
     Priority := tpLower;
     Resume;

  end;
end;

procedure TFrmTest.DataPrint;
var i : Integer;
begin

  with StringGrid do
  begin
    for i := 0 to 10000 do
    begin


      Cells[0,i] :=  IntToStr(i);     // 에러는 여기서 납니다. 루프가 잘 돌다가도 불규칙적으로 Access Violation 에러가 나더라구요.. ㅠㅠ

      Cells[1,i] :=  IntToStr(i);
      RowCount := RowCount +1;
    end;
  end;
  Label1.Caption := Label1.Caption + '완성!!!!';

end;


procedure TFrmTest.FormDestroy(Sender: TObject);
begin

  if Assigned(GridThread) then
  begin
    GridThread.Free;
    GridThread := Nil;
  end;


  if Assigned(BtnThread) then
  begin
    BtnThread.Free;
    BtnThread := Nil;
  end;

end;

procedure TFrmTest.BitBtn1Click(Sender: TObject);
begin
  if Assigned(BtnThread) then
  begin
    BtnThread.Free;
    BtnThread := Nil;
  end;
  BtnThread := TButtonThread.Create(True);

   BtnThread.Resume;
end;

{ ButtonThread }

procedure TButtonThread.ButtonStop;
begin
    FrmTest.Edit1.Text :=FrmTest.Edit1.Text + '멈춰!!!';
end;

procedure TButtonThread.Execute;
begin
  ButtonStop;
end;

end.


<!--CodeE-->
2  COMMENTS
  • Profile
    srookie 2006.06.21 02:22
    안녕하세요.
    아무래도 생성하신 Thread와 Main Thread간의 충돌로 예상되는군요.
    말씀을 드리자면, Main Thread에서는 화면에 Grid를 Update하려고 GDI함수를 이용하여 그리고 있는데, 생성하신 Thread에서는 Grid 객체에 계속 값들을 집어넣어서 생기는 문제 같습니다.
    일반적으로 Main Thread가 아닌 다른 Thread에서는 GDI 객체를 다루는 것이 좋지 않습니다.
    에러가 나지 않게 하려면 Syncronize라는 함수를 사용하세요.
    물론 Synchronize 자체도 Main Form의 Queue에 Job을 올려서 Main Thread에서 수행케 하는 원리라 Thread를 쓰는 의미는 없지만 말이죠.
    아니면 Grid 자체를 상속받아서 값을 쓰고 읽을 때 Thread Safe하게 고치셔야 할 듯 싶네요.
    즐프하세요.


  • Profile
    채태숙 2006.06.21 19:29
    헉.. 그런 심오한 뜻이 ... 좀더 내공을 쌓아야겠군요.. 감사합니다.

    말씀해주신 방법대로 처리해보겠습니다