Domanda

Ho bisogno di un timer equivalente che eseguirà periodicamente alcune azioni specifiche (ad esempio aggiornando alcuni progressi nel database o controllano nuovi lavori da eseguire in un database).

Queste azioni sono legate a un waithandle che specifica se il lavoro deve essere eseguito o meno. Quindi fondamentalmente questo potrebbe essere, ad esempio, un autoresetevent che è impostato dall'esterno quando c'è una nuova entità in un database e attiva la ricerca di queste nuove entità. Il timer è necessario perché voglio limitare il numero di query al database. Quindi, se arrivano 10 nuove notifiche, AutomaticResevent verrà impostata solo una volta e ci sarà anche una sola domanda per tutti questi.

I miei primi tentativi sembrano questo:

class ConditionalScheduler
{
    public void AddConditionalAction(WaitHandle handle, Action action)
    {
        lock (syncRoot)
        {
            handles.Add(handle);
            actions.Add(handle, action);
        }
    }

    private readonly object syncRoot = new object();

    private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>();
    private readonly List<WaitHandle> handles = new List<WaitHandle>();

    public void RunTimerLoop()
    {
        do
        {
            WaitHandle[] waitHandles = handles.ToArray();
            int index = WaitHandle.WaitAny(waitHandles);

            if (index >= 0)
            {
                WaitHandle handle = waitHandles[index];

                Action action;
                lock (syncRoot)
                {
                    action = actions[handle];
                }

                action();
            }
            Thread.Sleep(5000);
        } while (true);
    }

Il problema con questo approccio è che WaitHandle.Waitany mi darà solo l'indice del primo waithandle che viene attivato. Quindi, se ho 2 o più waithandles che vengono attivati, allora eseguirò solo le prime azioni e non le altre.

Hai un design migliore per ottenere i risultati richiesti per l'esecuzione di tutte le azioni attivate nel periodo di tempo specificato? Se semplifica la questione, potrei usare un altro tipo di meccanismo di notifica anziché i waithandles.

Grazie!

È stato utile?

Soluzione

Forse potresti andare con una coda a due thread / esecuzione sfusa? Nota che il codice Down è solo un concetto che sto scrivendo senza Visual Studio, quindi sto facendo in un elenco, questo è stato meglio essere fatto con una coda ma non ricordo la sintassi senza intellisense :)

private readonly Dictionary<WaitHandle, Action> actions = new Dictionary<WaitHandle, Action>();
    private readonly List<WaitHandle> handles = new List<WaitHandle>();
    private readonly List<WaitHandle> triggeredHandles = new List<WaitHandle>();

// thread 1
    public void CheckLoop()
    {
        do
        {
            WaitHandle[] waitHandles = handles.ToArray();
            int index = WaitHandle.WaitAny(waitHandles);

            if (index >= 0)
            {
                lock (triggeredHandles)
                {
                   triggeredHandles.Add(waitHandles[index]);
                }

            }            
        } while (true);
    }

// thread 2
public void RunLoop()
    {
        do
        {
            lock(triggeredHandles)
            {
                foreach (var th in triggeredHandles) {

                   Action action;
                   lock (syncRoot)
                   {
                       action = actions[th];
                   }

                   action();                   
                }
                triggeredHandles.Clear();
            }
            Thread.Sleep(5000);
        } while (true);
    }

Altri suggerimenti

Hai preso in considerazione l'uso delle classi di timer incorporate? System.Threading.Timer è un'implementazione leggera che utilizza il ThreadPool, o System.Timers.Timer che fornisce eventi correlati e più funzionalità.

Probabilmente ti risparmierai un sacco di problemi usando Estensioni reattive (RX) - Ha molti ottimi modi per comporre eventi nel modo in cui stai richiedendo.

Questo sito è un modo utile per vedere il tipo di cose che Rx può fare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top