10
votes

Invoquer un délégué sur un thread spécifique c #

Y a-t-il un moyen de faire fonctionner un délégué sur un thread spécifique?

Dis avoir: P>

CustomDelegate del = someObject.someFunction;
Thread dedicatedThread = ThreadList[x];


0 commentaires

5 Réponses :


2
votes

Normalement, je suggérerais d'utiliser simplement une piscine de thread ou Travail d'arrière-plan Code>, mais ceux-ci ne garantissent pas que le travail se produira sur un thread particulier. On ne sait pas pourquoi vous vous souciez de quel fil dirige les œuvres, mais en supposant que cela comporte une manière d'une manière ou d'une autre ...

Vous devriez passer à l'objet code> code> par une sorte de mémoire partagée, comme une file d'attente. Le fil de fond devrait regarder cette file d'attente, tirer les délégués de celui-ci quand ils existent et les exécuter. P>

S'il s'avère que la piscine de thread est acceptable pour exécuter votre code, vous pouvez toujours utiliser le BeginInvoke Code> Méthode du délégué pour le faire: P>

// wrap your custom delegate in an action for simplicity ...
Action someCode = () => yourCustomDelegate( p1, p2, p3, ... );
// asynchronously execute the currying Action delegate on the threadpool...
someCode.BeginInvoke( someCode.EndInvoke, action );


0 commentaires

2
votes

Malheureusement, il n'y a vraiment rien de construit pour le faire sur n'importe quel fil générique. Vous pouvez y accomplir en créant une classe qui enveloppe un thread et des implements Isynchonizeinvoke.

Une approche simple consiste à créer une file d'attente de traitement de l'événement sur le fil dédié que Lbushkin mentionne. Je suggère d'utiliser une catégorie Queue et appelez directement le délégué d'action. Vous pouvez accomplir la plupart des tâches dont vous auriez besoin d'utiliser des actions de délégués anonymes.

Enfin, comme un mot d'avertissement, je vous suggère d'utiliser un sémaphore ou eventwaithandle au lieu de thread.sleep sur votre fil dédié. Il est définitivement plus sympathique que d'exécuter votre boucle de fond encore et encore lorsque son inutile.


2 commentaires

Merci, j'avais l'intention de courir la boucle de fond encore et encore. Je vais regarder dans un événement gestionnaire d'attente


Je suis d'accord avec l'avertissement sur thread.sleep ; Toutefois, l'OP devrait mettre en œuvre synchronisationContext plutôt que le député isynchronizeinvoke .



0
votes

Pour les threads que vous créez, vous ne pouvez spécifier que le délégué threadstart lorsque vous les créez. Il n'y a aucune disposition pour injecter un délégué différent dans un fil créé. La piscine de thread est différente en ce qu'elle vous permet de soumettre des délégués à des threads créés précédemment qu'il commence en votre nom.

Ce n'est pas clair quel problème vous essayez de résoudre. Qu'essayez-vous d'accomplir (ou d'éviter) en essayant de courir plusieurs délégués sur un fil?


0 commentaires

3
votes

Je pense que la meilleure solution consiste à utiliser tâche les objets et la file d'attente vers un STATHREADSCHEDULER Exécution d'un seul fil.

Alternativement, vous pouvez utiliser le ActionThread dans Nito.Async pour créer Un fil normal avec une file d'attente intégrée de action délégués.

Cependant, aucun de ceux-ci ne traitera directement d'un autre besoin: la possibilité de "mettre en pause" une action et de continuer avec un autre. Pour ce faire, vous auriez besoin de saupoudrer «points de synchronisation» tout au long de chaque action et avoir un moyen de sauver son état, de la festes de la revoir et de poursuivre l'action suivante.

Toute cette complexité approche presque un système de planification de fil, alors je recommande de prendre un pas en arrière et de faire plus d'une nouvelle conception. Vous pouvez permettre à chaque action d'être mise en file d'attente sur le threadpool (je recommande de simplement avoir chacun une autre tâche objet). Vous aurez toujours besoin de saupoudrer de «points de synchronisation», mais au lieu de sauver l'état et de les repenser, vous devez simplement faire une pause (bloquer).


2 commentaires

Merci d'avoir souligné l'action de l'action, cela semble très utile. J'avais besoin d'encapsuler du code externe sur lequel j'ai peu de contrôle dans un fil. Tout ce que j'ai, c'est des délégués au code externe. Si je peux assurer que l'objet est dans un fil particulier, je peux "mettre en pause" cet objet en suspensant simplement le fil. Je ne pense pas que le threadpool me permettra de "mettre en pause" l'objet gentiment.


Un mot d'avertissement: il est possible (même probablement) de causer des blocages accidentellement en suspendant / reprendre des threads. Si possible, changez le code externe. Si cela n'est pas possible, envisagez d'utiliser des priorités de thread au lieu de suspendre / de reprendre.



0
votes

Un motif avec des points de synchronisation. Une caractéristique est que le thread du travailleur peut être démarré avant ou après le blocage des appels de travail. C'était pour un wrapper d'objet COM appelé Watin pour manipuler des instances d'Internet Explorer, comme un petit bébé pleurant, extrêmement sensible au contexte. L'amélioration peut être de supprimer le fichier thread.sleep () code>, éventuellement avec un autoréfortezevent code>, qui améliorerait considérablement les performances dans certaines situations.

L'idée de ce modèle était de Justin Breitfeller's, Stephen Cleary's, et les réponses de Lbushkin. P>

    private Instantiate()
    {
        BrowserQueue = new ConcurrentQueue<BrowserAction>();
        BrowserThread = new Thread(new ThreadStart(BrowserThreadLoop));
        BrowserThread.SetApartmentState(ApartmentState.STA);
        BrowserThread.Name = "BrowserThread";
        BrowserThread.Start();
    }
    private static void BrowserThreadLoop()
    {
        while (true)
        {
            Thread.Sleep(500);
            BrowserAction act = null;
            while (Instance.BrowserQueue.TryDequeue(out act))
            {
                try
                {
                    act.Action();
                }
                catch (Exception ex) { }
                finally
                {
                    act.CompletionToken.Set();
                }
            }
        }
    }
    public static void RunBrowserAction(Action act)
    {
        BrowserAction ba = new BrowserAction() { Action = act, CompletionToken = new ManualResetEvent(false) };
        Instance.BrowserQueue.Enqueue(ba);
        ba.CompletionToken.WaitOne();
    }
    public class BrowserAction
    {
        public Action Action { get; set; } = null;
        public ManualResetEvent CompletionToken { get; set; } = null;
    }
    ConcurrentQueue<BrowserAction> BrowserQueue;


0 commentaires