我需要做一些类似下面的代码。注意,由于.Net中的锁的性质(我将在代码之后解决这个问题),这不起作用,但我需要某种形式的实现,像这样的工作,但我不知道该怎么做。
static object lockMethod = new object();
static object lockTask = new object();
public static string testLocksAndTasks()
{
//This method is fast executing code but to prevent other issues, I
//lock this method. This might be impertinent to the base need of this
//question, but since I do use a lock on the entire requesting method, I
//put it here. This is because I integrate some logging and a bit of
//other logic on static variables so I just lock the method. This entire
//function is fast. The really slow code is in
//DoWorkInOtherThreadMethod(), which is why it needs to run in a
//background task.
lock (lockMethod)
{
if (Monitor.TryEnter(lockTask))
{
Task.Run(DoWorkInOtherThreadMethod)
.ContinueWith(ct=>
Monitor.Exit(lockTask)); //Oop! Unlocking on separate task NOT ALLOWED!
return "We locked lockTask and started the thread!";
}
else return "Task called and executed by other request!";
}
}
上面的代码清楚地说明了我要完成的任务。(从Web请求执行),我需要测试从请求启动的任务是否已经在另一个线程中运行。(本例中为lockTask
),并在运行时阻止将来的调用,并向调用方报告ack后台任务的状态。如果lockTask
已在使用中,我特别需要返回“Task X is already running for Y item”。(注意,我没有包括已经在运行的任务的额外信息,但这并不难做到,并且本示例不需要。)
我的代码理论上可以工作,因为一旦整个任务完成,对ContinueWith()
的调用将为任务解锁。但是,我发现这会引发错误,因为lockTask
上的初始锁是在一个线程中创建的,然后在另一个线程上使用Monitor.Exit(lockTask
进行后续解锁,这是不允许的。
我可以尝试将我的代码重组为下面提供的代码,但这也有我需要的问题。
public static string testLocksAndTasks()
{
lock (lockMethod)
{
//Check if we're locked!
if (!Monitor.IsEntered(lockTask))
{
Task.Run(()=>
{
//We weren't locked, so TryEnter...
if (Monitor.TryEnter(lockTask))
{
DoWorkInOtherThreadMethod();
Monitor.Exit(lockTask); //NOTE: I KNOW THIS SHOULD BE WRAPPED IN A
//TRY/CATCH/FINALLY. I'm just keeping sample
//the code simple.
}
else
{
//Oh no! This is actually quite possible, but this is a case I never
//want to reach?! I can't report this back to the initial call to
//testLocksAndTasks since we are in a new thread!
}
});
return "We locked lockTask and started the thread!";
}
else return "Task called and executed by other request!";
}
}
我在上面的评论中概括了一个明显的问题。我可以在任务中创建我的任务锁,这解决了锁和退出发生在不同线程上的第一个问题。然而,这引入了一个不同的但仍然重要的问题。
由于这段代码可以在多个请求线程中半同时执行,因此可能会有多个对!Monitor.IsEntered(lockTask)
的调用返回true,因为直到在新任务中发出Monitor.TryEnter(...)
请求时才设置锁。这不是问题,但是,我现在无法向testLocksAndTasks()
返回正确的状态响应。
如何正确地实现这样的功能,即锁定长时间运行的任务,同时报告它是否正在运行?
1条答案
按热度按时间sczxawaw1#
听起来你不需要锁,而是需要一个简单的标志来指示任务是否正在运行。现在要读取和设置这个标志,你可以使用常规锁。所以你检查标志,并在必要时在锁内启动任务。当任务完成时,你再次在锁内设置标志。示例代码: