2009-11-16 2 views
0

Si j'ai le thread A qui est le thread d'application principal et un thread secondaire. Comment puis-je vérifier si une fonction est appelée dans le thread B?Comment puis-je vérifier si une fonction est appelée sur un thread particulier?

Fondamentalement, je suis en train de mettre en œuvre le code suivant snippit:

public void ensureRunningOnCorrectThread() 
{ 
    if(function is being called within ThreadB) 
    { 
     performIO() 
    } 
    else 
    { 
     // call performIO so that it is called (invoked?) on ThreadB 
    } 
} 

Est-il possible d'effectuer cette fonctionnalité dans C# ou est-il une meilleure façon de voir le problème?

EDIT 1

J'ai remarqué ce qui suit dans la documentation MSDN, mais Im un dit douteux quant à savoir si ou non son une bonne chose à faire! :

// if function is being called within ThreadB 
if(System.Threading.Thread.CurrentThread.Equals(ThreadB)) 
{ 

} 

EDIT 2

Je me rends compte que Im regardant ce problème dans le mauvais sens (grâce aux réponses ci-dessous qui m'a aidé à voir cela) tout ce que je me soucie de est que l'IO ne se passe pas sur ThreadA. Cela signifie que cela peut se produire sur ThreadB ou tout autre thread, par ex. un BackgroundWorker. J'ai décidé que la création d'un nouveau BackgroundWorker dans la partie else de l'instruction f ci-dessus garantit que l'E/S est exécutée de manière non bloquante. Je ne suis pas entièrement sûr que c'est la meilleure solution à mon problème, mais il semble fonctionner!

Répondre

5

est ici une façon de le faire:

if (System.Threading.Thread.CurrentThread.ManagedThreadId == ThreadB.ManagedThreadId) 
      ... 

Je ne connais pas assez Thread la mise en œuvre de la classe de .NET pour savoir si la comparaison ci-dessus est équivalente à Equals() ou non, mais en l'absence de ces connaissances, comparer les ID est un pari sûr.

Il peut y avoir un meilleur (où mieux = plus facile, plus rapide, etc.) façon d'accomplir ce que vous essayez de faire, selon quelques choses comme:

  • quel type d'application (ASP .NET, WinForms, console, etc.) construisez-vous? Pourquoi voulez-vous imposer des E/S sur un seul thread?
  • quel type d'E/S est-ce? (par exemple, écrit dans un fichier? I/O réseau contraint à un socket? etc.)
  • Quelles sont vos contraintes de performance par rapport au coût de verrouillage, au nombre de threads de travail concurrents, etc.?
  • si le « else » clause dans votre code doit être le blocage, le feu et oublier, ou quelque chose de plus sophistiqué
  • comment vous voulez traiter Temporisations, blocages, etc.

L'ajout de cette Les informations à votre question vous seront utiles, bien que si votre application WinForms est la vôtre et que vous parlez des E/S de l'interface utilisateur utilisateur, vous pouvez ignorer les autres questions car le scénario est évident. Gardez à l'esprit que la mise en œuvre // call performIO so that it is called (invoked?) on ThreadB varie selon qu'il s'agit de WinForms, ASP.NET, console, etc.

Si WinForms, consultez this CodeProject post pour une manière fraîche de le manipuler. Voir également MSDN pour savoir comment cela est généralement géré en utilisant InvokeRequired.

Si la console ou l'application de serveur généralisée (sans interface graphique), vous devez trouver comment faire savoir au thread principal qu'il a du travail en attente - et vous pouvez envisager une autre implémentation qui a un I/O thread de travail ou pool de threads qui se contente d'exécuter les demandes d'E/S en file d'attente que vous faites la queue. Ou vous pouvez envisager de synchroniser vos demandes d'E/S (plus facile) au lieu de rassembler les appels sur un thread (plus difficile).

Si ASP.NET, vous implémentez probablement cela dans le mauvais sens. Il est généralement plus efficace d'utiliser des pages asynchrones ASP.NET et/ou de synchroniser (par dessus) la synchronisation avec vos E/S en utilisant lock{} ou une autre méthode de synchronisation.

+0

J'imagine comparer juste l'ID est beaucoup plus efficace que la comparaison de l'objet entier! J'étudie aussi les façons dont je peux forcer à exécuter sur le thread ThreadB plutôt que sur le Thread actuel. Des idées? –

+0

Jetez un oeil à ma réponse mise à jour ci-dessus-- est-ce que cela répond à ce que vous essayez de faire? –

+0

TK, comparer l'Id n'est pas plus efficace que de comparer 2 objets, mais il est plus fiable ici. –

1

La partie else de votre extrait, Invoke PerformIO on ThreadB ne fonctionnera que lorsque ThreadB est le thread principal exécutant un Messageloop.

Alors peut-être que vous devriez repenser ce que vous faites ici, ce n'est pas une construction normale.

1

Ce que vous essayez de faire est le contraire de ce que la propriété InvokeRequired d'un contrôle de formulaire Windows ne, donc si elle est une application sous forme de fenêtre, vous pouvez simplement utiliser la propriété de votre formulaire principal:

if (InvokeRequired) { 
    // running in a separate thread 
} else { 
    // running in the main thread, so needs to send the task to the worker thread 
} 
1

Votre thread secondaire fait-il autre chose que la fonction performIO()? Si non, alors un moyen facile de le faire est d'utiliser un System.Threading.ManualResetEvent. Avoir le thread secondaire assis dans une boucle while en attente de l'événement à définir. Lorsque l'événement est signalé, le thread secondaire peut effectuer le traitement d'E/S. Pour signaler l'événement, demandez au thread principal d'appeler la méthode Set() de l'objet événement.

using System.Threading; 
static void Main(string[] args) 
{ 
    ManualResetEvent processEvent = new ManualResetEvent(false); 
    Thread thread = new Thread(delegate() { 
     while (processEvent.WaitOne()) { 
      performIO(); 
      processEvent.Reset(); // reset for next pass... 
     } 
    }); 
    thread.Name = "I/O Processing Thread"; // name the thread 
    thread.Start(); 

    // Do GUI stuff... 

    // When time to perform the IO processing, signal the event. 
    processEvent.Set(); 
} 

aussi, en aparté, prendre l'habitude de nommer des objets System.Threading.Thread comme ils sont créés. Lorsque vous créez le thread secondaire, définissez le nom du thread via la propriété Name. Cela vous aidera lorsque vous regardez la fenêtre Threads dans les sessions de débogage, et il vous permet également d'imprimer le nom du thread sur la console ou la fenêtre de sortie si l'identité du thread est toujours en doute.

Questions connexes