Bonjour,
Voici en quelques lignes le projet:
Il s'agit d'une application windows testant des temps de réactivité de l'utilisateur. Elle émet donc un signal et mesure le temps entre le signal et la réaction de l'utilisateur.
Je suis parti sur un modèle multithread afin que le code qui lance le signal et attend ne pénalise pas l'interface utilisateur.
Mon form principal possède un backgroundworker qui lance une classe chargée d’émettre le signal (son) et d'attendre la réaction de l'utilisateur
J'ai donc le code suivant:
Dans le form principal
Dans ma classe AudioTestsWorker
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 AudioTestsWorker runningTest; private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // This event handler is where the actual work is done. // This method runs on the background thread. // Get the BackgroundWorker object that raised this event. System.ComponentModel.BackgroundWorker bgWorker; bgWorker = (System.ComponentModel.BackgroundWorker)sender; // Get the Worker object and call the main method. AudioTestsWorker wk = (AudioTestsWorker)e.Argument; wk.RunTest(bgWorker, e, 10); } private void StartWorkerThread() { // Initialize the object that the background worker calls. runningTest = new AudioTestsWorker(); // Start the asynchronous operation. backgroundWorker1.RunWorkerAsync(runningTest); } private void Form1_KeyDown(object sender, KeyEventArgs e) { if (runningTest != null) runningTest.KeyPressed(DateTime.Now); }
Donc le thread enfant lance le son, et attend jusqu'à 20sec pour déclarer qu'on n'a pas réagit à temps.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class AudioTestsWorker { protected DateTime _startTime; protected DateTime _keyTime; protected Boolean _keyPressed; protected int[] _results; public void RunTest( System.ComponentModel.BackgroundWorker worker, System.ComponentModel.DoWorkEventArgs e, int count) { _results = new int[count]; for (int cpt=0;cpt<count;cpt++) { if (worker.CancellationPending) { e.Cancel = true; break; } else { worker.ReportProgress(0, cpt+1); } Random rnd = new Random(unchecked((int)(DateTime.Now.Ticks))); int waitTime = rnd.Next(6000); Thread.Sleep(waitTime); _keyPressed = false; SystemSounds.Beep.Play(); _startTime = DateTime.Now; for (int cpt2 = 0; cpt2 < 20; cpt2++) { if (_keyPressed) break; Thread.Sleep(1000); } if (!_keyPressed) throw new Exception("Vous n'avez pas appuyé dans les temps"); else _results[cpt] = (_keyTime - _startTime).Milliseconds; } } public void KeyPressed(DateTime keyTime) { if (!_keyPressed) { _keyPressed = true; _keyTime = keyTime; } } }
Comme le thread enfant est bloqué en sleep, c'est le form principal qui capte le keypress et le passe au thread enfant.
Donc tout se passe bien, les temps de réaction sont bien mesurés mais... et oui, il y a un mais...
Au moment où l'utilisateur presse une touche, l'application effet un bip de mécontentement.
Apres reflexion, je me demande si ce n'est pas la ligne suivante (en fin du mainform):
Qui rale car j'appelle une méthode sur un thread en sleep et du coup, ça pose probleme
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 runningTest.KeyPressed(DateTime.Now);
si c'est bien ça, comment appréhender ce genre de problématique ???
J'ai pensé à une autre approche:
Le form principal gére l'emission du signal et en note la date/heure.
Ce dernier ne se bloque pas en sleep et ne fait rien.
La méthode keypress note la date/heure de la réaction de l'utilisateur.
Jusque là tout est beau, aucun thread n'est bloqué et tout devrait bien se passer. Mais il faut mettre en place un timeout et ne pas attendre indéfiniment que l'utilisateur réagisse.
Du coup, j'ai pensé faire un thread enfant juste pour attendre, avec un sleep(20000)
Donc le form lance le signal, note la date/heure et déclenche le thread enfant.
Si une touche est pressée, le form principal coupe le thread enfant, et calcule le temps de réaction
Si le thread enfant arrive à son temps écoulé, il se ferme et le form, alors déclare qu'il y a eu timeout dans une méthode backgroundWorker1_RunWorkerCompleted
N'est ce pas mieux ?
Merci d'avance pour votre aide
Partager