C# 为什么我的代码抛出“信号量已被释放”异常?
在我的代码中,我使用了C# 为什么我的代码抛出“信号量已被释放”异常?,c#,wpf,task,C#,Wpf,Task,在我的代码中,我使用了SemaphoreSlim,在执行了整个for循环之后,我从App.g.csexception接收到信号量已被释放,如果仅通过使用语句来释放,我无法找出原因。以下是通常使用的整个方法的代码: public async Task TestHistoricalResultsAsync() { //init values and controls CommandStartedControlsSetup("TestResultsCommand"); Lis
SemaphoreSlim
,在执行了整个for
循环之后,我从App.g.cs
exception接收到信号量已被释放
,如果仅通过使用
语句来释放,我无法找出原因。以下是通常使用的整个方法的代码:
public async Task TestHistoricalResultsAsync()
{
//init values and controls
CommandStartedControlsSetup("TestResultsCommand");
List<Task> tasks = new List<Task>();
int degreeOfParallelism = 10;
int loopCounter = 0;
ProgressBarTick("Testing on historic data", loopCounter, Races.Count, 0);
using (var throttler = new SemaphoreSlim(degreeOfParallelism))
{
//for all races in the file
for (int i = 0; i < Races.Count; i++)
{
int j = i;
if (TaskCancellation == true)
{
break;
}
await throttler.WaitAsync(TokenSource.Token);
tasks.Add(Task.Run(() => //async
{
try
{
CancellationToken.ThrowIfCancellationRequested();
//if the race is from 2018
if (Races[j].RaceDate.Year == 2018)
{
Category = Races[j].RaceCategory;
Distance = Races[j].RaceDistance.ToString();
//for all horses in the race
for (int h = 0; h < Races[j].HorseList.Count; h++)
{
if (TaskCancellation == true)
{
break;
}
CancellationToken.ThrowIfCancellationRequested();
HorseDataWrapper horse = new HorseDataWrapper();
horse = ParseHorseData(Races[j].HorseList[h], Races[j].RaceDate);
Races[j].HorseList[h] = horse; //get all indexes
}
}
}
catch (Exception e)
{
//
}
finally
{
loopCounter++;
ProgressBarTick("Testing on historic data", loopCounter, Races.Count, 0);
throttler.Release();
}
}));
}
}
try
{
//ThreadPool.SetMinThreads(100, 100);
await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
//
}
finally
{
await _dataServices.SaveRaceTestResultsAsync(Races.ToList()); //save the analysis to the file
AllControlsEnabled = true;
CommandCompletedControlsSetup();
VisibilityCancellingMsg = Visibility.Collapsed;
}
}
公共异步任务TestHistoricalResultsAsync()
{
//初始化值和控件
CommandStartedControlsSetup(“TestResultCommand”);
列表任务=新列表();
int degreeOfParallelism=10;
int循环计数器=0;
ProgressBarTick(“历史数据测试”,循环计数器,Races.Count,0);
使用(var节流器=新信号量lim(degreeOfParallelism))
{
//对于文件中的所有种族
for(int i=0;i//异步
{
尝试
{
CancellationToken.ThrowIfCancellationRequested();
//如果比赛从2018年开始
如果(比赛[j].RaceDate.Year==2018)
{
类别=种族[j]。种族类别;
距离=赛道[j]。赛道距离。ToString();
//所有参赛的马
对于(int h=0;h
根据评论讨论,问题是您的信号量超出了范围。您有两个选择:
a) 等待区块内所有任务的执行
using (var throttler = new SemaphoreSlim(degreeOfParallelism))
{
// setup the tasks
try
{
await Task.WhenAll(tasks);
}
// ...
}
b) 在所有任务的执行完成后手动处置
var throttler = new SemaphoreSlim(degreeOfParallelism)
{
// setup the tasks. You can still use a scope block (brackets) here if you want.
}
try
{
await Task.WhenAll(tasks);
// ...
}
finally
{
throttler?.Dispose()
}
第二个选项很可能更合适,但它取决于代码的最终布局。根据评论讨论,问题是您的信号量超出了范围。您有两个选择: a) 等待区块内所有任务的执行
using (var throttler = new SemaphoreSlim(degreeOfParallelism))
{
// setup the tasks
try
{
await Task.WhenAll(tasks);
}
// ...
}
b) 在所有任务的执行完成后手动处置
var throttler = new SemaphoreSlim(degreeOfParallelism)
{
// setup the tasks. You can still use a scope block (brackets) here if you want.
}
try
{
await Task.WhenAll(tasks);
// ...
}
finally
{
throttler?.Dispose()
}
第二个选项很可能更合适,但它取决于代码的最终布局。因为
throttler
在执行任务之前超出了using语句的范围。关键是任务是异步的,那么为什么要使用using
块,而该块只有在它们是同步的情况下才能工作呢?如果您真的想,您需要保留任务。当所有调用using
块以防止其被处置时。@ClausJørgensen I基于此示例,您建议使用摆脱,并手动处置?或者Release
正在处理它?好吧,在执行所有任务之前,您不能处理信号量。因此,您需要使用
块等待它们在内全部完成,或者手动处理。这两种选择都取决于您想要如何构造代码。并注意在示例中,如何等待Task.WhenAll(tasks)
是在中使用
block.bakunet调用的:您误解了作用域在C#中的工作方式。基本上,using语句的作用域完成了,因为它内部没有执行任何操作,您只是将块附加到数组中。之后信号量被释放,然后首先执行任务(使用已释放的信号量)。我认为您现在应该只进行手动处理,这样更容易理解作用域是如何以这种方式工作的。(基本上在示例代码的最后一块中处理)Task.Run
说(基本上)“以后再做”。而later
是在Dispose
之后发生的using
导致的。因为throttler
在任务执行之前超出了using语句的范围。关键是任务是异步的,那么为什么要使用using
块,而该块只有在它们是同步的情况下才能工作呢?如果您真的想,您需要保留任务。当所有调用using
块以防止其被处置时。@ClausJørgensen I基于此示例,您建议使用摆脱,并手动处置?或者Release
正在处理它?好吧,在执行所有任务之前,您不能处理信号量。因此,您需要使用
块等待它们在内全部完成,或者手动处理。这两种选择都取决于你想怎么做