안녕하세요.. 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-->
아무래도 생성하신 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하게 고치셔야 할 듯 싶네요.
즐프하세요.