我很难理解此处的并发性以及排除锁的放置位置。
思想是为客户端知道的每台服务器创建一个线程。在编译时不知道服务器。客户端作为随时间变化的服务器的视图。每个线程(通过远程调用与服务器通信的线程)都放在taskArray上,该线程随后返回到调用函数,根据许多因素在该函数上执行WaitAll,WaitAny和其他类型的Wait。
问题是,当我有N台服务器时,说三台。所有这三个任务都调用了副本服务器上的第三台服务器,有时是第二台服务器。
如果我将睡眠代码放置在For循环中,则无论我正在运行多少台服务器,一切都会按预期运行。但是,像这样的硬编码从来都不是一个好主意,我正在寻找一个可以确切解释这里发生了什么(我怀疑)或者至少应该锁定哪些变量的人。因为我尝试在睡眠之前锁定的设备并没有解决问题。
我创建每个任务的代码是这样的:
private Task<ReplyData>[] InitiateServerCalls(List<ServerData> replicasList, XuLiskovRequest request, CancellationToken cancellationToken)
{
int replicasCount = replicasList.Count;
ServerData serverData;
RequestData requestData;
Task<ReplyData>[] tasksArray = new Task<ReplyData>[replicasCount];
try
{
for (int ridx = 0; ridx < replicasCount; ridx++)
{
Thread.Sleep(250);
serverData = replicasList[ridx];
requestData = request.RequestData;
tasksArray[ridx] = new Task<ReplyData>(() => CallServer(serverData, requestData, cancellationToken), cancellationToken);
tasksArray[ridx].Start();
}
}
catch (RemotingException) { RequestViewChange(); }
return tasksArray;
}
每个线程应运行的方法如下:
private ReplyData CallServer(ServerData serverData, RequestData requestData, CancellationToken token)
{
string serverProxyURL;
IServerService server_proxy;
token.ThrowIfCancellationRequested();
serverProxyURL = $"tcp://{serverData.ServerURL}/{serverData.ServerId}";
Utils.Print($" [*] Asking {serverData.ServerId} to execute request...");
server_proxy = (IServerService)Activator.GetObject(typeof(IServerService), serverProxyURL);
return server_proxy.Request(requestData);
}
答案 0 :(得分:2)
serverData
和requestDat
的值错误地被封闭在Task的lamda中。将变量的声明移入循环应该可以减轻这种情况
private Task<ReplyData>[] InitiateServerCalls(List<ServerData> replicasList, XuLiskovRequest request, CancellationToken cancellationToken)
{
int replicasCount = replicasList.Count;
Task<ReplyData>[] tasksArray = new Task<ReplyData>[replicasCount];
try
{
for (int ridx = 0; ridx < replicasCount; ridx++)
{
Thread.Sleep(250);
ServerData serverData = replicasList[ridx];
RequestData requestData = request.RequestData;
tasksArray[ridx] = new Task<ReplyData>(() => CallServer(serverData, requestData, cancellationToken), cancellationToken);
tasksArray[ridx].Start();
}
}
catch (RemotingException) { RequestViewChange(); }
return tasksArray;
}