gpt4 book ai didi

multithreading - 保护两个线程的字符串缓冲区?

转载 作者:行者123 更新时间:2023-12-03 18:08:24 25 4
gpt4 key购买 nike

我正在通过 Indy 套接字处理流式数据包字符串,在客户端,我有一个线程从 TIdTCPClient 读取传入数据,并不断将此数据附加到单个字符串的末尾缓冲。我有另一个线程从头开始连续读取这个缓冲区,根据需要复制(和删除)数据(一次一个完整的数据包)。

我知道在任何情况下,两个线程访问同一个变量都是危险的。但这也适用于字符串吗?还是只是对象?从两个不同的线程读取/写入相同的字符串,我可以放心吗?如果不是,那我应该怎么做才能保护这个字符串呢?这是一个名为 FBuffer 的普通字符串。

我像这样将数据附加到末尾:

procedure TListenThread.CheckForData;
begin
if FClientSocket.Connected then begin
FClientSocket.IOHandler.CheckForDataOnSource(5000);
if not FClientSocket.IOHandler.InputBufferIsEmpty then
FBuffer:= FBuffer + FClientSocket.IOHandler.InputBufferAsString;
end;
end;

另一个线程是这样读的:

procedeure TPacketThread.CheckForPacket;
var
P: Integer; //Deliminator position
T: String; //Temp copying string
Z: Integer; //Expected packet size
begin
P:= Pos('#', FBuffer);
if P > 0 then begin //Is the deliminator found?
T:= Copy(FBuffer, 1, P-1); //Copy up to deliminator...
Z:= StrToIntDef(T, 0); //Convert packet size to integer...
if Z > 0 then begin
//Is there a full packet waiting in buffer?
if Length(FBuffer) >= Z then begin
//First, delete size definition and deliminator...
Delete(FBuffer, 1, P);
//Now grab the rest of it up to the packet size...
T:= Copy(FBuffer, 1, Z);
//Delete what we just copied...
Delete(FBuffer, 1, Z);
//Finally, pass this packet string for further processing...
ProcessPacket(T);
end;
end;
end;
end;

该代码是我的代码的简化版本,只是为了演示我需要使用 FBuffer 完成的所有工作。

最佳答案

是的,您必须保护字符串缓冲区免受并发访问。 Indy 有一个 TIdThreadSafeString 类,您可以将其用于该目的,例如:

FBuffer: TIdThreadSafeString;
// make sure to Create() and Free() as needed..

.

procedure TListenThread.CheckForData; 
begin
if FClientSocket.Connected then begin
FClientSocket.IOHandler.CheckForDataOnSource(5000);
if not FClientSocket.IOHandler.InputBufferIsEmpty then
FBuffer.Append(FClientSocket.IOHandler.InputBufferAsString);
end;
end;

.

procedure TPacketThread.CheckForPacket; 
var
P: Integer; //Deliminator position
T: String; //Temp copying string
Z: Integer; //Expected packet size
begin
FBuffer.Lock;
try
P:= Pos('#', FBuffer.Value);
if P > 0 then begin //Is the deliminator found?
T := Copy(FBuffer.Value, 1, P-1); //Copy up to deliminator...
Z := StrToIntDef(T, 0); //Convert packet size to integer...
if Z > 0 then begin
//Is there a full packet waiting in buffer?
if Length(FBuffer.Value) >= Z then begin
//First, delete size definition and deliminator...
FBuffer.Value := Copy(FBuffer.Value, P+1, MaxInt);
//Now grab the rest of it up to the packet size...
T := Copy(FBuffer.Value, 1, Z);
//Delete what we just copied...
FBuffer.Value := Copy(FBuffer.Value, Z+1, MaxInt);
//Finally, pass this packet string for further processing...
ProcessPacket(T);
end;
end;
end;
finally
FBuffer.Unlock;
end;
end;

话虽如此,鉴于您所展示的有关数据包格式的内容,我会采取不同的策略:

FBuffer: TIdThreadSafeStringList;
// make sure to Create() and Free() as needed..

.

procedure TListenThread.CheckForData; 
var
T: String; //Temp copying string
Z: Integer; //Expected packet size
begin
if FClientSocket.Connected then begin
if FClientSocket.IOHandler.InputBufferIsEmpty then begin
FClientSocket.IOHandler.CheckForDataOnSource(5000);
if FClientSocket.IOHandler.InputBufferIsEmpty then Exit;
end;
// data is available, keep reading as long as packets are present...
repeat
T := FClientSocket.IOHandler.ReadLn('#');
Z := StrToIntDef(T, 0);
if Z > 0 then begin
T := FClientSocket.IOHandler.ReadString(Z);
FBuffer.Add(T);
end;
until FClientSocket.IOHandler.InputBufferIsEmpty;
end;
end;

.

procedure TPacketThread.CheckForPacket; 
var
L: TStringList;
T: String;
begin
L := FBuffer.Lock;
try
if L.Count = 0 then Exit;
T := L[0];
L.Delete(0);
finally
FBuffer.Unlock;
end;
ProcessPacket(T);
end;

关于multithreading - 保护两个线程的字符串缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11128641/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com