我有以下存储颜色值的类:
TMyColors = class
private
Colors: array [0 .. MaxCols - 1, 0 .. MaxRows - 1] of TColor;
public
NumColumns: Cardinal;
NumRows: Cardinal;
function GetColor1(col, row: Integer): TColor;
function GetColor2(col, row: Integer): TColor;
end;
function TMyColors.GetColor1(col, row: Integer): TColor;
begin
Result := Colors[col, row];
end;
function TMyColors.GetColor2(col, row: Integer): TColor;
begin
if InRange(col, 0, NumColumns - 1) and InRange(row, 0, NumRows - 1) then
Result := Colors[col, row]
else
Result := 0;
end;
NumColumns和NumRows表示实际使用的列和行的数量。
此类应用作多线程应用程序中的全局变量,例如
type
TMyThread = class(TThread)
...
function GetColor1(col, row: Integer): TColor;
function GetColor2(col, row: Integer): TColor;
...
end;
var
MyColors: TMyColors;
MyThread1, MyThread2, MyThread3: TMyThread;
function TMyThread.GetColor1(col, row: Integer): TColor;
begin
Result := MyColors.GetColor1(col, row);
{ Alternative:
if InRange(col, 0, MyColors.NumColumns - 1) and InRange(row, 0, MyColors.NumRows - 1) then
Result := MyColors.GetColor1(col, row)
else
Result := 0;
}
end;
function TMyThread.GetColor2(col, row: Integer): TColor;
begin
Result := MyColors.GetColor2(col, row);
end;
也就是说,所有线程都访问全局变量MyColors中的值。我假设,在这种情况下,GetColor1的使用是线程安全的,即,它可以在多个线程中同时使用(当然,前提是没有其他线程修改Colors的内容)。我还假设,GetColor2不是线程安全的。
我仍然不确定什么时候是线程安全的,什么时候不是,所以有人能证实上面的假设是正确的吗?
1条答案
按热度按时间7hiiyaii1#
根据定义,如果代码以这样的方式操作数据,即使用该数据的多个线程根据代码规范正确地行为,并且不会导致任何意外的交互,则代码是线程安全的。
如果可以同时访问某些数据的所有线程(包括主线程)都只读取该数据,则线程之间不可能有任何意外的交互,因为数据在被读取时不会更改。当至少一个线程在其他线程阅读数据时也修改了数据,并且检索到的数据可能处于不一致状态时,就会发生并发问题。
由于上述原因,它使用的某些代码和数据的线程安全性取决于上下文及其使用方式。
对于您的示例,您的数据由几个部分组成:
MyColors
全局变量,以及MyColors
变量引用的TMyColors
示例中的数据-Colors
、NumColumns
、NumRows
。同样,如果所有线程只读取上述数据中的任何一个,无论是直接读取还是通过
GetColor1
和GetColor2
方法读取,那么这些代码都是线程安全的。当涉及到写入时,情况更加复杂,并且取决于您正在修改的数据:
MyColors
全局变量:给新示例赋值MyColors :=
,那么没有什么是线程安全的Colors
数组被写入,则它不是线程安全的NumColumns
或NumRows
正在被写入,则GetColor2
不是线程安全,因为它使用这些字段,但是仅使用Colors
字段的GetColors1
即使在这种情况下也是线程安全的在方法中使用局部变量是线程安全的,因为每次调用方法时,这些局部变量都是在本地分配的,其他线程不会对它们产生影响。
在方法中访问参数是线程安全的但是参数的线程安全性稍微复杂一些,因为线程安全性取决于它们的类型(引用类型的线程安全性还取决于其他线程是否可以访问引用所指向的相同数据)以及它们在传递给方法的代码中的更广泛上下文中是否是线程安全的。换句话说,如果你把变量传递给一个方法,而这个变量可以在那个时候被另一个线程写入,那么这样的代码就不是线程安全的。