1

我有一个从程序的多个区域调用的方法(我们称之为“CheckAll”),因此可以在第一次完成之前第二次调用它。

为了解决这个问题,我实现了一个“锁”(如果我理解正确的话),它会暂停第二个线程,直到第一个线程完成。

但是,我真正想要的是第二次调用立即返回调用方法(而不是暂停线程),并安排 CheckAll 在第一次完成后再次运行。

我可以设置一个计时器来执行此操作,但这似乎既麻烦又困难。有没有更好的办法?

4

3 回答 3

1

简单/便宜的实施。

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 检查并等待任何等待线程。)

快乐的编码...

于 2012-10-04T03:52:18.293 回答
1

使用单独的线程在同样等待信号量的循环中调用 CheckAll()。'PerformCheck()' 方法向信号量发出信号。

然后,您的系统可以从任何线程尽可能多地调用“PerformCheck()”,并且 CheckAll() 将运行的次数与 PerformCheck() 调用的次数完全相同,但不会阻塞 PerformCheck() .

没有标志,没有限制,没有锁定,没有轮询。

于 2012-10-04T09:39:47.793 回答
0

您可以为此设置一个标志。

当此 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;
}
}
于 2012-10-04T03:51:17.313 回答