初学线程,遇上问题,特来请教前辈们。先行谢过。(100分)

  • 主题发起人 主题发起人 Pc 狂迷
  • 开始时间 开始时间
P

Pc 狂迷

Unregistered / Unconfirmed
GUEST, unregistred user!
我想用 5 个线程产生 5 个不同的 [1..20] 的随机数,就写了这个 互斥同步 线程。
可得到的结果并不是我想要的 -- 有零。(为 BUG 更明显 我加了一句 sleep),前辈
们帮忙看看错在哪里?
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
ThreadRuning = class(TThread)
protected
procedure Execute;override;
end;

TfrmMain = class(TForm)
btnGO: TButton;
procedure btnGOClick(Sender: TObject);
private
procedure ThreadsDone(Sender: TObject);
public
{ Public declarations }
end;

var
frmMain: TfrmMain;
implementation
{$R *.dfm}
const
ID = 5;
var
PNumber: array [1..ID] of integer;
Flags : integer = 0;
do
neFlags : integer = 0;
hMutex: THandle = 0;
PWNuberSet: Set of 1..20;
procedure ThreadRuning.Execute;
var
Number: integer;
LoopBool: boolean;
begin
LoopBool := True;
// Number := 0;
FreeOnTerminate := True;
OnTerminate := frmMain.ThreadsDone;
Inc(Flags);
while LoopBooldo
begin
if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0 then
begin
Number := Random(20) + 1;
if not(Number in PWNuberSet) then
begin
PNumber[Flags] := Number;
Include(PWNuberSet,Number);
LoopBool := false;
sleep(100);
end;
//if
end;
// if
end;
// while
end;

procedure TfrmMain.ThreadsDone(Sender: TObject);
var
i: integer;
begin
Inc(DoneFlags);
ifdo
neFlags = 5 then
begin
for i := 1 to 5do
ShowMessage(IntToStr(i) + ' : ' + IntToStr(PNumber));
CloseHandle(hMutex);
ShowMessage('End');
end;
// if
end;

procedure TfrmMain.btnGOClick(Sender: TObject);
begin
Flags := 0;
do
neFlags := 0;
PWNuberSet := PWNuberSet * [];
Randomize;
hMutex := CreateMutex(nil,false,nil);
ThreadRuning.Create(false);
ThreadRuning.Create(false);
ThreadRuning.Create(false);
ThreadRuning.Create(false);
ThreadRuning.Create(false);
end;

end.
 
hMutex := CreateMutex(nil, false, Pchar('test'));
给互斥对象启个名字:)
 

if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0 then
begin
Number := Random(20) + 1;
if not(Number in PWNuberSet) then
begin
PNumber[Flags] := Number;
Include(PWNuberSet,Number);
LoopBool := false;
sleep(100);
end;
//if
end;
// if

少了一句 releasemutex(hmutex);
对象未释放;加在end;
// while 前面
 
释放了,我的想法是在 5 条线程都执行完后才 释放,但不知这样做是否正确:
procedure TfrmMain.ThreadsDone(Sender: TObject);
var
i: integer;
begin
Inc(DoneFlags);
ifdo
neFlags = 5 then
begin
for i := 1 to 5do
ShowMessage(IntToStr(i) + ' : ' + IntToStr(PNumber));
[red]CloseHandle(hMutex);[/red]
ShowMessage('End');
end;
// if
end;
 
...他的意思是 releasemutex(hmutex);之后 其他的线程才能进入
procedure ThreadRuning.Execute;
var
Number: integer;
LoopBool: boolean;
hMutex: THandle;
begin
LoopBool := True;
FreeOnTerminate := True;
OnTerminate := frmMain.ThreadsDone;
hMutex := CreateMutex(nil, false, pchar('test'));
Inc(Flags);
while LoopBooldo
begin
if WaitForSingleObject(hMutex, 10000) = WAIT_OBJECT_0 then
begin
Number := Random(20) + 1;
if not (Number in PWNuberSet) then
begin
PNumber[Flags] := Number;
Include(PWNuberSet, Number);
LoopBool := false;
ReleaseMutex(hMutex);
sleep(100);
end;
//if
end;
// if
end;
// while
CloseHandle(hMutex);
end;
 
我将 Number := Random(20) + 1;
改为 5 ,并加了个链表进行跟踪记录:
type
Link = ^node;
node = Record
Flag: integer;
date: integer;
next: link;
end;
//record
var
Test: link;
...
while LoopBooldo
begin
if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0 then
begin
Number := Random(5) + 1;
New(q);
q^.Flag := Flags;
q^.date := Number;
q^.next := Test;
Test := q;
if not(Number in PWNuberSet) then
begin
PrizewiningNumber[Flags] := Number;
Include(PWNuberSet,Number);
LoopBool := false;
ReleaseMutex(hMutex);
Sleep(200);
end;
//if
end;
// if
end;
// while
... 发现 有几条线程根本就没进入过 if WaitForSingleObject 块。 ReleaseMutex(hMutex);
并没什么效。
 
ReleaseMutex()
和closemutex不一样的
你按我上面说的试试
 
不好意思,
早上给你发的时候掉线了,
现在才回来
 
Unit Unit1;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
Type
TForm1 = Class(TForm)
Button1: TButton;
Label1: TLabel;
Edit1: TEdit;
Memo1: TMemo;
Procedure Button1Click(Sender: TObject);
Private
{ Private declarations }
Public
Procedure ThreadDone(Sender: TObject);
{ Public declarations }
end;

ThreadTest = Class(TTHread)
Protected
Procedure Execute;
Override;
end;

Const MaxSize = 128;
Var
Form1: TForm1;
NextNumber: integer = 0;
Gogal: Array[0..MaxSize] Of Integer;
ThreadFlag: Integer = 0;
CS: TRTLCriticalSection;

Implementation
{$R *.DFM}
Function GetNextNumber: integer;
begin
Result := NextNumber;
Inc(NextNumber);
end;

Procedure THreadTest.Execute;
Var i: integer;
begin
FreeOnTerminate := True;
OnTerminate := Form1.ThreadDone;
EnterCriticalSection(CS);
For i := 0 To MaxSizedo
Gogal := GetnextNumber;

LeaveCriticalSection(CS);
end;

Procedure TForm1.ThreadDone(Sender: TObject);
Var i: integer;
begin
Inc(ThreadFlag);
If ThreadFlag = 2 then
begin
Memo1.Lines.Clear;
For i := 0 To MaxSizedo
Memo1.Lines.add(IntTostr(Gogal));
DeleteCriticalSection(CS);
Button1.Enabled := true;
end;
end;

Procedure TForm1.Button1Click(Sender: TObject);
Var i: integer;
begin
Button1.Enabled := False;
ThreadFlag := 0;
InitializeCriticalSection(CS);
For i := 0 To strtoint(Edit1.Text)-1do
ThreadTest.Create(false);
end;

end.

这是我的例子,以前的,用的是临界区
还有的是用CREATEMUTEX,这个好象用来做线程互斥我有点忘了,
你可以看D5开发人员指南:)
 
while LoopBooldo
begin
if WaitForSingleObject(hMutex,INFINITE) = WAIT_OBJECT_0 then
begin
Number := Random(20) + 1;
if not(Number in PWNuberSet) then
begin
PNumber[Flags] := Number;
Include(PWNuberSet,Number);
LoopBool := false;
ReleaseMutex(hMutex);///////////////////加入这个
sleep(100);
end;
//if
end;
// if
end;
// while
end;
 
埃,你们都钻牛角尖了,他数据不对的原因并不是线程冲突的原因......
procedure ThreadRuning.Execute;
var
Number: integer;
LoopBool: boolean;
hMutex: THandle;
l_Flag : integer;//这个变量很重要保存该线程对应的下标,仔细想一下引入这个变量的作用把
begin
LoopBool := True;
FreeOnTerminate := True;
OnTerminate := frmMain.ThreadsDone;
hMutex := CreateMutex(nil, false, pchar('test'));
Inc(Flags);
//*****************
l_Flag :=Flags;
//******************
while LoopBooldo
begin
if WaitForSingleObject(hMutex, 100000) = WAIT_OBJECT_0 then
begin
frmMain.ListBox2.Items.Add (inttostr(l_Flag));
Number := Random(20) + 1;
if not (Number in PWNuberSet) then
begin
PNumber[l_Flag] := Number;
Include(PWNuberSet, Number);
LoopBool := false;
sleep(20);
ReleaseMutex(hMutex);
end;
end;
end;

CloseHandle(hMutex);
end;
 
康师傅击中要害,得 100 分!
 
后退
顶部