我有一个从程序的多个区域调用的方法(我们称之为“CheckAll”),因此可以在第一次完成之前第二次调用它。
为了解决这个问题,我实现了一个“锁”(如果我理解正确的话),它会暂停第二个线程,直到第一个线程完成。
但是,我真正想要的是第二次调用立即返回调用方法(而不是暂停线程),并安排 CheckAll 在第一次完成后再次运行。
我可以设置一个计时器来执行此操作,但这似乎既麻烦又困难。有没有更好的办法?
我有一个从程序的多个区域调用的方法(我们称之为“CheckAll”),因此可以在第一次完成之前第二次调用它。
为了解决这个问题,我实现了一个“锁”(如果我理解正确的话),它会暂停第二个线程,直到第一个线程完成。
但是,我真正想要的是第二次调用立即返回调用方法(而不是暂停线程),并安排 CheckAll 在第一次完成后再次运行。
我可以设置一个计时器来执行此操作,但这似乎既麻烦又困难。有没有更好的办法?
简单/便宜的实施。
private Thread checkThread = null;
private int requests = 0;
void CheckAll()
{
lock(SyncRoot){
if (checkThread != null; && checkThread.ThreadState == ThreadState.Running)
{
requests++;
return;
}else
{
CheckAllImpl();
}
}
}
void CheckAppImpl()
{
// start a new thread and run the following code in it.
checkThread = new Thread(newThreadStart( () => {
while (true)
{
// 1. Do what ever checkall need to do.
// 2.
lock (SyncRoot)
{
requests--;
if (!(requests > 0))
break;
}
}});
checkThread.Start();
}
顺便说一句,这可能有一些竞争条件。更好的实现应该是使用.NET 4 中引入的ConcurrentQueue,它可以为您处理所有的线程疯狂。
更新:这是一个使用 ConcurrentQueue 的更“酷”的实现(结果我们不需要 TPL。)
public class CheckAllService
{
// Make sure you don't create multiple
// instances of this class. Make it a singleton.
// Holds all the pending requests
private ConcurrentQueue<object> requests = new ConcurrentQueue<object>();
private object syncLock = new object();
private Thread checkAllThread;
/// <summary>
/// Requests to Check All. This request is async,
/// and will be serviced when all pending requests
/// are serviced (if any).
/// </summary>
public void RequestCheckAll()
{
requests.Enqueue("Process this Scotty...");
lock (syncLock)
{ // Lock is to make sure we don't create multiple threads.
if (checkAllThread == null ||
checkAllThread.ThreadState != ThreadState.Running)
{
checkAllThread = new Thread(new ThreadStart(ListenAndProcessRequests));
checkAllThread.Start();
}
}
}
private void ListenAndProcessRequests()
{
while (requests.Count != 0)
{
object thisRequestData;
requests.TryDequeue(out thisRequestData);
try
{
CheckAllImpl();
}
catch (Exception ex)
{
// TODO: Log error ?
// Can't afford to fail.
// Failing the thread will cause all
// waiting requests to delay until another
// request come in.
}
}
}
protected void CheckAllImpl()
{
throw new NotImplementedException("Check all is not gonna write it-self...");
// TODO: Check All
}
}
注意:我使用真正的线程而不是 TPL 任务,因为任务不会保留真正的线程作为优化。当没有线程时,这意味着在您的应用程序关闭时,任何等待的 CheckAll 请求都将被忽略。(当我认为我非常聪明地可以在一个任务中调用我的日志记录方法时,我被这个咬得很厉害,忽略了几个关闭时的十几个日志记录。当优雅退出时,CLR 检查并等待任何等待线程。)
快乐的编码...
使用单独的线程在同样等待信号量的循环中调用 CheckAll()。'PerformCheck()' 方法向信号量发出信号。
然后,您的系统可以从任何线程尽可能多地调用“PerformCheck()”,并且 CheckAll() 将运行的次数与 PerformCheck() 调用的次数完全相同,但不会阻塞 PerformCheck() .
没有标志,没有限制,没有锁定,没有轮询。
您可以为此设置一个标志。
当此 CheckAll() 方法运行时。在此方法的末尾,您可以为每个单独的方法放置一个标志。意味着如果该方法是从其他方法调用的让我们说 a() 然后在此之后立即从 b() 调用它然后>>>当从 a() 调用它时放置一个 flaga 变量(可能是全局的) 最后在 CheckAll() 中(将其分配给特定值)并根据 flaga 变量值在 b() 中给出条件。像这样的意思...
public a()
{
CheckAll();
}
public b()
{
.
.
(put condition here for check when flaga=1 from the method CheckAll())
CheckAll();
}
public CheckAll()
{
.
.
.
flaga=1;
}
}