Multithreading 如何从单独的单元执行线程同步
我有以下问题 我有一个名为“myGlobalFunctions.pas”的单元。 在本单元中,我实施了多个项目使用的程序/功能 项目1使用本单元 项目3使用本单元 项目6使用本单元 等 在“项目1”中,有一个线程使用“全局函数”单元中的函数 在项目3中没有线程,但使用了函数 到目前为止,这个线程(project1)几乎没有提供应用程序接口的更新,更新是在从“myGlobalFunctions.pas”调用函数之后或之前进行的 如“启动前功能1” ... 召唤 “在功能1之后” 这样我就可以知道程序在做什么 但是现在我想在应用程序接口的“function1”更新中实现(使用synchronize) 我想在应用程序界面“处理步骤1…xx记录”中反映。(数据集有一个while循环) 对“project1”使用同步,并与普通label1.caption='message'同步;任何其他项目的application.process消息 可能吗 我怎么能做这样的事 线程安全吗 很多 拉兹万 这里有一些代码可以更好地理解Multithreading 如何从单独的单元执行线程同步,multithreading,delphi,Multithreading,Delphi,我有以下问题 我有一个名为“myGlobalFunctions.pas”的单元。 在本单元中,我实施了多个项目使用的程序/功能 项目1使用本单元 项目3使用本单元 项目6使用本单元 等 在“项目1”中,有一个线程使用“全局函数”单元中的函数 在项目3中没有线程,但使用了函数 到目前为止,这个线程(project1)几乎没有提供应用程序接口的更新,更新是在从“myGlobalFunctions.pas”调用函数之后或之前进行的 如“启动前功能1” ... 召唤 “在功能1之后” 这样我就可以知道程
THREAD UNIT
procedure TThreadSyncronizeProcess.SignalStart;
begin
frmMain.sbMain.Panels[2].Text := 'Syncronizare in desfasurare...'; -- exist all the time
if Assigned(frmSyncronize) then begin -- check if exist this
frmSyncronize.logMain.WriteFeedBackMessage('Pornire syncronizare...', '', EVENTLOG_INFORMATION_TYPE, True);
end;
end;
procedure TThreadSyncronizeProcess.Execute;
var ..... declarations
begin
Synchronize(SignalStart); -- this is normal call within thread update interface
try
try
workSession := TIB_Session.Create(nil);
workDatabase := TIB_Database.Create(workSession);
... creating more components and setup them ...
uSyncronizareFunctions.SetupDatabase(workDatabase, workSession, transactionWrite, transactionRead);
uSyncronizareFunctions.SetupDataSnapConnection(workConnectionRead, providerRead);
if Assigned(frmSyncronize) then begin
uSyncronizareFunctions.SetupFeedBack(frmSyncronize.logMain);
end;
try
Synchronize(SignalMessage);
// this next function is from the "global unit"
isAllOk := uSyncronizareFunctions.ImportOperatoriAutorizati(workImage, workLabelProgress, True);
isAllOk := isAllOk and uSyncronizareFunctions.ImportJudete;
isAllOk := isAllOk and uSyncronizareFunctions.ImportLocalitati;
isAllOk := isAllOk and uSyncronizareFunctions.ImportUM;
isAllOk := isAllOk and uSyncronizareFunctions.ImportFurnizori;
isAllOk := isAllOk and uSyncronizareFunctions.ImportClasificari;
except
on e : Exception do begin
raise Exception.Create(dmMain.GetDataSnapExceptionMessage(e.Message));
end;
end;
except
on e : Exception do begin
baseMessage := e.Message;
Synchronize(SignalMessage);
end;
end;
finally
workDatabase.ForceDisconnect;
FreeAndNil(transactionRead);
... etc
end;
Synchronize(SignalFinish);
end;
global function unit
unit uSyncronizareFunctions;
function ImportOperatoriAutorizati(imgDone : TImage; labelProgress : TLabel; isThread : Boolean) : Boolean;
var workQuery : TIB_Query;
serverData : TClientDataSet;
begin
Result := True;
try
... create all that we need
serverData.Close;
serverData.CommandText := 'SELECT * FROM OPERATORI_AUTORIZATI WHERE REC_VERSION > :ARECVERSION ORDER BY REC_VERSION, ID';
serverData.Params.Clear;
serverData.Params.CreateParam(ftInteger, 'ARECVERSION', ptInput);
serverData.Params.ParamByName('ARECVERSION').AsInteger := lastVersion;
serverData.Active := True;
...... I want here to signal start
while not serverData.Eof do begin
try
globalInsert_Tran.StartTransaction;
workQuery.Close;
workQuery.ParamByName('AIDGLOBAL').AsString := serverData.FieldByName('IDGLOBAL').AsString;
workQuery.Open;
if workQuery.IsEmpty then begin
workQuery.Insert;
workQuery.FieldByName('IDGLOBAL').AsString := serverData.FieldByName('IDGLOBAL').AsString;
end else begin
workQuery.Edit;
end;
workQuery.FieldByName('NUME').AsString := serverData.FieldByName('NUME').AsString;
workQuery.FieldByName('COD_AUTORIZARE').AsString := serverData.FieldByName('COD_AUTORIZARE').AsString;
workQuery.FieldByName('OTHER_INFO').AsString := serverData.FieldByName('OTHER_INFO').AsString;
workQuery.FieldByName('DATASTERGERE').AsVariant := GetValueDate(serverData.FieldByName('DATASTERGERE').AsDateTime);
workQuery.FieldByName('REC_VERSION').AsInteger := serverData.FieldByName('REC_VERSION').AsInteger;
workQuery.Post;
MarkRecordAsDirtyFalse(workQuery);
globalInsert_Tran.Commit;
...... I want here to signal progress and to see in the application interface "processing record xx/100" or any other message
except
on e : Exception do begin
Result := False;
globalInsert_Tran.Rollback;
end;
end;
serverData.Next;
end;
finally
FreeAndNil(serverData);
FreeAndNil(workQuery);
end;
end;
看起来您希望您的全局函数执行回调。您可以尝试以下方法:
unit MyGlobalMethods;
interface
uses
System.SysUtils;
type
// define a method signature for your callback
TSomeCallback = procedure(progress : integer) of object;
// add a callback argument to your function (initializing to nil will make
// the parameter optional and will not break your previous implementations)
function GlobalFunction(arg1 : integer;
AMethodCallback : TSomeCallback = nil) : boolean;
implementation
function GlobalFunction(arg1 : integer;
AMethodCallback : TSomeCallback) : boolean;
var i : integer;
begin
for i := 0 to arg1 do begin
sleep(10); // Do some work
// report progress by executing the callback method
// only do this if a method has been passed as argument
if (i mod 100 = 0) and (Assigned(AMethodCallback)) then AMethodCallback(i);
end;
result := true;
end;
end.
添加一个方法回调作为参数,允许您传入任何希望该方法执行的函数。例如:
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
procedure UpdateProgress(progress : integer);
end;
TSomeThread = class(TThread)
private
FProgressCallback : TSomeCallback;
FProgress : integer;
procedure SynchronizeCallback(progress : integer);
procedure DoCallback;
public
procedure Execute; override;
property OnFunctionProgress : TSomeCallback
read FProgressCallback write FProgressCallback;
end;
实施为:
procedure TSomeThread.Execute;
begin
GlobalFunction(1000, SynchronizeCallback);
end;
procedure TSomeThread.SynchronizeCallback(progress: Integer);
begin
FProgress := progress;
Synchronize(DoCallback);
end;
procedure TSomeThread.DoCallback;
begin
if Assigned(FProgressCallback) then FProgressCallback(FProgress);
end;
您还没有告诉我们您使用的是什么版本的Delphi。如果您使用的是D2009或更高版本,您可以使用匿名方法将上述两个调用捆绑到一个调用中(并摆脱FProgress
):
在您的表格中,您将执行以下操作:
procedure TForm1.UpdateProgress(progress: Integer);
begin
label1.Caption := IntToStr(progress);
end;
procedure TForm1.Button1Click(Sender: TObject);
var someThread : TSomeThread;
begin
someThread := TSomeThread.Create(true);
someThread.FreeOnTerminate := true;
someThread.OnFunctionProgress := UpdateProgress;
someThread.Start;
end;
这很好地划分了责任。主窗体将更新方法传递给线程(在本例中是更新标签的方法)。线程负责同步调用和全局函数,因此不需要关心它正在执行的回调是否来自主线程或任何其他线程。线程知道它需要同步该方法,因此它应该承担相应的责任。请包含代码的相关部分,以便我们可以尝试帮助您。您的描述非常模糊,代码将有助于使其更加清晰。(请发布足够的代码来澄清您的问题;请不要在这里倾吐大量代码,并期望我们尝试解决它。)谢谢。如果我理解您的意思是正确的,那么您有一个线程,根据它在哪个应用程序中使用,它的行为应该是不同的。区别在于与主线程的同步应该执行不同的code.nope。我希望一个常规函数对一个线程和另一个普通单元的行为有所不同。全局函数不需要知道代码是否在主线程中执行。为开始信号提供一个回调方法,为进度更新提供另一个回调方法。线程代码也应该与GUI的依赖性分离。这也可以通过回调@J…来处理。。。解释.tks以获取信息。事实上,这似乎是一种优雅的做法。我不完全明白。。。。因为我从来没有和callback一起工作过。在了解了什么是callback之后。。我可以说一个很好的答案,你让我睁大了眼睛。
procedure TForm1.UpdateProgress(progress: Integer);
begin
label1.Caption := IntToStr(progress);
end;
procedure TForm1.Button1Click(Sender: TObject);
var someThread : TSomeThread;
begin
someThread := TSomeThread.Create(true);
someThread.FreeOnTerminate := true;
someThread.OnFunctionProgress := UpdateProgress;
someThread.Start;
end;