2016-07-23 6 views
5

Il y a (ou il y a eu) beaucoup de discussions sur le fait qu'il est bon ou mauvais d'utiliser la méthode Thread.Sleep(). D'après ce que je comprends, il doit principalement être utilisé à des fins de débogage.La mise en boucle Thread.Sleep() serait-elle mauvaise pour la performance lorsqu'elle est utilisée pour mettre en pause un thread?

Maintenant, je me demande: est-il mauvais à utiliser dans mon but spécifique, c'est-à-dire en le bouclant constamment pour pouvoir mettre en pause/reprendre le fil? Je fais ceci parce que je veux mettre en pause un fil qui effectue des opérations d'E/S et être capable de le reprendre d'une manière simple. Les opérations d'E/S consistent simplement à écrire des blocs de 4 096 octets dans un fichier jusqu'à ce que toutes les données y aient été écrites. Comme le fichier peut être volumineux et prendre beaucoup de temps, je veux pouvoir mettre l'opération en pause (au cas où il commencerait à manger beaucoup de ressources système).

Mon code, la version VB.NET:

'Class level. 
Private BytesWritten As Long = 0 
Private Pause As Boolean = False 

'Method (thread) level. 
While BytesWritten < [target file size] 
    ...write 4096 byte buffer to file... 

    While Pause = True 
     Thread.Sleep(250) 
    End While 

    ...do some more stuff... 
End While 

C# équivalent:

//Class level. 
long bytesWritten = 0; 
bool pause = false; 

//Method (thread) level. 
while(bytesWritten < [target file size]) { 
    ...write 4096 byte buffer to file... 

    while(pause == true) { 
     Thread.Sleep(250); 
    } 

    ...do some more stuff... 
} 

J'ai entendu parler ResetEvents et je sais un peu ce qu'ils font, mais j'ai jamais vraiment regardé beaucoup dans eux.

+2

Je voudrais utiliser un événement de réinitialisation manuelle. Après chaque morceau, attendez l'événement. Pour mettre le fil en pause, réinitialisez l'événement. Pour reprendre le fil, définissez l'événement. –

+2

Je ne comprends pas pourquoi vous voudriez * faire une pause * * une longue opération *. Sûrement cela le fera juste prendre plus de temps. Si vous voulez que le fichier soit écrit de manière asynchrone, pourquoi ne pas simplement utiliser le fichier asynchrone IO et attendre le résultat? –

+1

@EricLippert: Ceci est pour si l'utilisateur de mon application veut mettre en pause, car l'opération pourrait consommer beaucoup de ressources système. –

Répondre

3

Je pense que, sur la base de la description, je ferais ce

'Class level. 
Private BytesWritten As Long = 0 
Private NotPaused As New Threading.ManualResetEvent(True) 

Le changement dans le nom de la variable est approprié puisque c'est la façon dont il serait utilisé

'Method (thread) level. 
    While BytesWritten < [target file size] 
     '...write 4096 byte buffer to file... 

     NotPaused.WaitOne(-1) 

     '...do some more stuff... 
    End While 

Pour faire la pause de la boucle faire cela

NotPaused.Reset() 

et de continuer

NotPaused.Set() 
+1

Merci. Cette solution convient mieux car 'ManualResetEvent' est seulement" ouvert "ou" fermé ", à part le' sémaphore 'qui semble être ouvert pour un nombre d'appels xx. Maintenant vous m'avez aussi appris un peu comment 'ManualResetEvents' fonctionne! –

1

Je pense que la manière la plus élégante est de faire dormir le thread indéfiniment jusqu'à ce qu'il soit réveillé par un autre thread appelant Thread.Interrupt sur le premier thread qui dort. Il y a un bon exemple de ceci avec l'exemple de code: Pausing and Resuming Threads.

+1

Interruption de threads est une mauvaise idée qui peut facilement conduire à des blocages. – Groo

+0

Merci pour la réponse. Mais j'étais, comme Groo, conscient de ce que Thread.Interrupt() pourrait causer des problèmes. –

+0

Merci pour la correction @Groo, j'aurais aussi dû réfléchir aux bonnes pratiques (à faire et à ne pas faire) en répondant à la question. – hankide

1

Je pourrais mal comprendre ce que vous essayez d'accomplir ici, mais d'après ce que je vois, il semble que vous essayez de bloquer un thread jusqu'à ce qu'une tâche d'E/S soit terminée. Sémaphores serait le meilleur pari ici, au lieu de faire Thread.Sleep().

La plupart des systèmes d'exploitation offrent des sémaphores de blocage qui mettent un thread en veille de manière permanente jusqu'à ce qu'un autre thread le réveille. Vous êtes probablement mieux de les utiliser au lieu de constamment faire cette vérification vous-même. Les deux Thread.Sleep() et les sémaphores de blocage mettent le thread en veille, mais ce dernier le fait perpétuellement jusqu'à ce que la ressource ait été libérée (le sémaphore a été signé). Le premier exige que le fil se réveille constamment, vérifie, et retourne dormir. Ce dernier enregistre ces cycles d'exécution.

+0

Désolé de ne pas être clair. Je n'essaie pas de bloquer jusqu'à ce qu'une opération d'E/S soit terminée, j'essaie de mettre en pause l'opération d'E/S. En gros, j'écris des tampons de données dans un fichier jusqu'à ce que toutes les données aient été écrites, car cela peut prendre un certain temps avant que je puisse mettre ce travail en pause. –

+0

J'ai également mis à jour ma question avec cette explication. –

+0

Bonne réponse! Des explications courtes et facilement compréhensibles! –

2

Dans .NET, il n'y a aucune raison d'utiliser Thread.Sleep en plus d'essayer de simuler des opérations longues pendant le test et/ou le débogage sur un thread MTA car il va bloquer. Une autre option serait peut-être d'utiliser le TPL. Puisque vous ne voulez pas bloquer vous pouvez utiliser Task.Delay. Comme vous le savez probablement, une tâche représente une opération asynchrone.