我正在编写一个Delphi dll,用于计算结果并将其写入CSV文件。调用程序是多线程的,因此一个问题是同时多次写入文件,这会导致调用程序崩溃。我试图使用关键部分来锁定文件写入,但是仍然会发生崩溃。如果我将程序配置为仅使用一个线程,问题将消失。下面是我的代码:
library Question;
uses
SysUtils,
Classes,
Math,
SyncObjs;
{$R *.res}
Var
Outputfile: textfile;
CriticalSection: TCriticalSection;
CalNumb: integer = 0;
PrintString: String;
Threadvar
Cal1, Cal2, Cal1Last: double;
Function Calculator (input1, input2, input3, input4: double;
Factor: double; LastCal: Boolean; Print: integer): double stdcall;
Const
Divisor = 4;
Var
Temp: double;
Begin
Cal1Last:= Cal1;
Cal1:= (input1+ input2+input3+ input4)/Divisor;
Cal2:= (Cal1+Factor*Cal1Last)/2;
Temp:= Cal2 - Cal1Last;
If LastCal and (Print = 1) then
begin
CriticalSection:= TCriticalSection.Create;
Try
Try
Inc(CalNumb);
Assign(Outputfile, 'C:\Calculator\Result.csv');
If FileExists('C:\Calculator\Result.csv') then
Append(Outputfile) else rewrite (Outputfile);
If CalNumb = 1 then
begin
PrintString:= 'CalNumb' + ',' + 'Cal1' + ',' +
'Cal1Last' + ',' + 'Cal2' + ',';
Writeln(Outputfile, PrintString);
end;
Writeln(Outputfile,
CalNumb, ',', Cal1:5:2, ',', Cal1Last:5:2, ',', Cal2:5:2, ',');
Finally
Close(Outputfile);
End;
Finally
CriticalSection.Free;
End;
end;
If Cal1 <> 0 then Calculator:= Temp/Cal1 else Calculator:= 0;
End;
Exports
Calculator;
begin
end.
我的代码中有任何错误吗?多线程计算和外部文件编写对于该项目至关重要。您有什么建议和意见吗?我是一个初学者,所以如果您可以在此处发布代码,对我来说将是很大的帮助。提前非常感谢您!///////////////////////////////////////////////////// ////////////////////////////////////////////////////
Graymatter,谢谢您的建议。在完成您建议的更改后,应用程序将崩溃,然后再写入文件。dll的早期版本可以在崩溃前将某些数据行写入文件。万一我可能进行错误的更改,请在下面发布更改的部分。该代码的另一部分未更改。
If LastCal and (Print = 1) then
begin
CriticalSection.Acquire;
Try
Try
Inc(CalNumb);
Assign(Outputfile, 'C:\Calculator\Result.csv');
If FileExists('C:\Calculator\Result.csv') then
Append(Outputfile) else rewrite (Outputfile);
If CalNumb = 1 then
begin
PrintString:= 'CalNumb' + ',' + 'Cal1' + ',' +
'Cal1Last' + ',' + 'Cal2' + ',';
Writeln(Outputfile, PrintString);
end;
Writeln(Outputfile,
CalNumb, ',', Cal1:5:2, ',', Cal1Last:5:2, ',', Cal2:5:2, ',');
Finally
Close(Outputfile);
End;
Finally
CriticalSection.Release;
End;
end;
If Cal1 <> 0 then Calculator:= Temp/Cal1 else Calculator:= 0;
End;
Exports
Calculator;
begin
end.
initialization
CriticalSection := TCriticalSection.Create;
finalization
CriticalSection.Free;
end;
创建关键部分对象不会进行任何锁定。您需要致电Acquire
以获取锁定并Release
释放锁定。
请参阅在线帮助中的使用关键部分。
问题是,在加载DLL时需要创建关键部分,因此您需要执行以下操作:
begin
...
CriticalSection.Acquire;
try
...
// The code that needs to be locked goes inside here.
// In your case it would be the code that opens the file
// and appends the data.
...
finally
CriticalSection.Release;
end;
...
end;
您将必须将代码移到一个单独的单元中,以便您可以包含initialization
和finalization
阻止。这些块将分别在首次加载DLL和卸载DLL时执行。
您的新单元将如下所示:
unit UnitForDLL;
interface
function Calculator(input1, input2, input3, input4: double;
Factor: double; LastCal: Boolean; Print: integer): double; stdcall;
implementation
uses
SyncObjs, SysUtils;
var
...
CriticalSection: TCriticalSection;
...
function Calculator(input1, input2, input3, input4: double;
Factor: double; LastCal: Boolean; Print: integer): double; stdcall;
begin
...
CriticalSection.Acquire;
try
...
// The code that needs to be locked goes inside here.
// In your case it would be the code that opens the file
// and appends the data.
...
finally
CriticalSection.Release;
end;
...
end;
initialization
CriticalSection := TCriticalSection.Create;
finalization
CriticalSection.Free;
end.
完成此操作后,您的项目本身将被更改为更加简单的内容:
library Question;
uses
SysUtils,
Classes,
UnitForDLL;
{$R *.res}
exports
Calculator;
begin
end.
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句