public void Queue(PendingAction action)
        {
            lock (this) {
                // Caso estremo: ci sono più di 5000000 di modifiche in sospeso! Aspetta prima di permetterne ulteriori accodamenti.
                while (_list.Count() == MAX_QUEUED_LIMIT)
                    Monitor.Wait(this);

                // Controllo se l'azione corrente è già in esecuzione dal thread Sync...
                PendingAction currentAction= SynchThread.Instance.GetWorkingAction();
                if (currentAction != null && action.FullPath == currentAction.FullPath)
                {
                    // Se il syncthread stava lavorando sullo steso file, annulla l'azione che sta compiendo perché sarebbe vana.
                    currentAction.Stop();
                    currentAction.Join();
                    SetDone(currentAction);
                }

                /*
                 * Se la richiesta è relativa ad un file che abbiamo già inserito nel dizionario,
                 * occorre spostarla in coda alla lista (in termini sequenziali), aggiornando
                 * l'indice nel dizionario relativo alla lista.
                 */
                if (_dict.ContainsKey(action.FullPath))
                {
                    _list.Remove(action.FullPath);
                    _dict.Remove(action.FullPath);
                }

                _list.Add(action.FullPath);
                _dict.Add(action.FullPath, action);

                Monitor.Pulse(this);

            }
        }
        /// <summary>
        /// Rimuoviamo un'azione appena soddisfatta.
        /// </summary>
        /// <param name="pa"></param>
        public void SetDone(PendingAction pa)
        {
            lock (this)
            {
                // La gestione del pull è differente dalle altre.
                if (pa is PendingPull)
                {
                    PendingPull pullAction = pa as PendingPull;
                    if (_pullNotifications > 1) {
                        _pullNotifications = 1;
                    }
                    else if (_pullNotifications > 0) {
                        _pullNotifications = 0;
                    }

                    _pullNotifications = 0;
                    // Altrimenti lascia tutto com'è, alla prossima invocazione di GetJob() verrà ritornato ancora un PullPending come actions
                    return;
                }
                else
                {
                    if (!_dict.ContainsKey(pa.FullPath))
                        throw new ApplicationException("Errore gravissimo! Si tenta di fare una setDone su un oggetto non più presente nel dizionario.");

                    _list.Remove(pa.FullPath);//Ricerca?!
                    _dict.Remove(pa.FullPath);
                }
            }
        }
        /// <summary>
        /// Questa è la funzione che il thread dovrà eseguire.
        /// </summary>
        private void Run()
        {
            while (!_switchOff)
            {
                while (!ApplicationState.Instance.STEnabled)
                {
                    lock (ApplicationState.Instance)
                    {
                        Monitor.Wait(ApplicationState.Instance);
                    }
                }
                _currentAction = PendingActions.Instance.GetJob();
                try
                {

                    if (_currentAction.Handle())
                    {
                        lock (_currentAction)
                        {
                            PendingActions.Instance.SetDone(_currentAction);
                            if (OnActionPerformed != null)
                                OnActionPerformed(new SynchThreadActionPerformedArgs(_currentAction));
                        }
                    }
                }
                catch (Exception e)
                {
                    // TODO log
                    // Notifica che è accadeuto un errore se qualcuno si è registrato all'evento.
                    if (OnError != null)
                    {
                        SynchThreadErrorArgs args = new SynchThreadErrorArgs(e, _currentAction);
                        OnError(args);
                    }
                }
                finally {
                    if (_currentAction != null)
                    {
                        _currentAction.SetEnd();
                        _currentAction = null;
                    }
                }
            }
        }
 public SynchThreadErrorArgs(Exception e, PendingAction pa)
 {
     _exception = e;
     _pa = pa;
 }
 public SynchThreadActionPerformedArgs(PendingAction pa)
 {
     _pa = pa;
 }