1

プログラムの複数の領域から呼び出されるメソッド (「CheckAll」と呼びましょう) があるため、1 回目が完了する前に 2 回目に呼び出すことができます。

これを回避するために、(正しく理解している場合) 1 番目のスレッドが完了するまで 2 番目のスレッドを停止する「ロック」を実装しました。

しかし、私が本当に望んでいるのは、この 2 回目の呼び出しが (スレッドを停止するのではなく) 呼び出し元のメソッドにすぐに戻り、1 回目の完了後に CheckAll が再度実行されるようにスケジュールすることです。

これを行うためにタイマーを設定することもできますが、それは面倒で難しいようです。より良い方法はありますか?

4

3 に答える 3

1

別のスレッドを使用して、セマフォでも待機するループで CheckAll() を呼び出します。「PerformCheck()」メソッドは、セマフォにシグナルを送ります。

その後、システムは任意のスレッドから必要なだけ「PerformCheck()」を呼び出すことができ、CheckAll() は PerformCheck() 呼び出しとまったく同じ回数実行されますが、PerformCheck() でブロックされることはありません。 .

フラグなし、制限なし、ロックなし、ポーリングなし。

于 2012-10-04T09:39:47.793 に答える
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 に答える
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 に答える