【发布时间】:2021-03-31 16:12:27
【问题描述】:
我对多线程有点困惑。 我目前正在使用 SinglaR 开发实时服务。这个想法是连接的用户可以向另一个用户请求数据。 下面是请求和响应函数的概要。
考虑以下代码:
private readonly ConcurrentBag _sharedObejcts= new ConcurrentBag();
请求:
[...]
var sharedObject = new MyObject();
_sharedObejcts.Add(sharedObject);
ForwardRequestFireAndForget();
try
{
await Task.Delay(30000, sharedObject.myCancellationToken);
}
catch
{
return sharedObject.ResponseProperty;
}
_myConcurrentBag.TryTake(sharedObject);
[...]
回应:
[...]
var result = DoSomePossiblyVeryLengthyTaskHere();
var sharedObject = ConcurrentBag
.Where(x)
.FirstOrDefault();
// The request has timed out so the object isn't there anymore.
if(sharedObject == null)
{
return someResponse;
}
sharedObject.ResponseProperty = result;
// triggers the cancellation source
sharedObject.Cancel();
return someOtherResponse;
[...]
所以基本上是向服务器发出请求,然后转发到另一台主机,然后函数等待取消或超时。
其他主机调用response函数,添加repsonseObject并触发myCancellationToken。
但是我不确定这是否代表竞争条件。
理论上,响应线程可以检索sharedObject,而另一个线程仍然位于 finally 块上吗?
这意味着,请求已经超时,任务还没有从包中取出对象,这意味着数据不一致。
有什么方法可以确保在Task.Delay() 调用之后首先调用的是TryTake()call?
【问题讨论】:
-
我不确定我是否正确理解了这个问题,但如果你想在任务完成后调用某些东西,你可以使用 ContinueWith
-
@Fake 但在执行
ContinueWith(Task)之前是否有其他线程检索共享对象,从而找到一个不应该存在的对象? -
@AsPas - 在尝试处理对象之前,请始终从
ConcurrentBag中删除对象。那么就没有竞争条件了。 -
但是如果他仍然准时,主机就没有办法访问该对象。
-
@AsPas - 哦,哇。我知道了。这是一种非常奇怪的做法。
标签: c# multithreading thread-safety signalr race-condition