This is a slightly weird setup, and I’m planning on redoing it, but, if nothing else, I’m hoping that I can learn a lot more about threading as a result of this.
At the moment, I’ve got an application I’m building which uses a TabControl Windows Form as the basis for its design. I’ve got a number of different things I need to do, so I figured this might be the best way to do it.
Now, I’m coding in a Macro function into the program, such that a user can record and playback mouse and keyboard actions. That has been perfectly fine, and mixing it with System.Timers.Timer has been ok as well. However, the DLL I’m using uses Thread.Sleep(x) to pause the thread in between keystroke and mouse executions.
At this point, the button is on a different tabpage and switches to a different page. However, the point blank setup resulted in the program hanging while waiting for the macro execution to complete.
To explain a little better:
- User clicks button in main tabcontrol.
- Tabcontrol.SelectedIndex is switched to the proper page, but does not refresh page (I tried calling this.Refresh(), it didn’t work)
- Macro executes
- Tabcontrol finishes loading the page, but by this point, the necessary macro has already executed and the loaded page is superfluous.
To get around this, I started researching threading and seeing how I could use that. I came up with the following code inside a class:
Class X{
Thread othread;
...
public void Play()
{
if ((othread != null) && !(othread.IsAlive))
{
othread = new Thread(playValues);
GC.Collect();
}
else if (othread == null) othread = new Thread(playValues);
else return;
othread.Start();
}
public void PlayValues(){
...
Thread.CurrentThread.Abort();
}
}
The reason why the thread is destroyed is because, every time the user clicks “Play” in the main form, X.Play() is called, so I need to either reuse the thread (I researched Monitor.Pulse(), but that gave me asynchronous call errors), or destroy it permanently each time it completes.
Now, at the moment, the code works fine. However, the fact that I’m consistently creating and destroying threads every time I have to play a macro is slightly concerning, and the ridiculous amount of GC calls is also worrying me.
Can I get some pointers on threading, and how I might be able to do this better, without this setup? As a point of fact, the secondary tab is a webpage, and the macros are executed on the webpage’s form.
- Edit: I don’t know if I didn’t make this clear, but the macro is using a mouse and keyboard simulator. The other tab is a webbrowser setup, and it nests an applet inside, so I’m emulating the hardware functions in order to perform automated setups. This helps because I don’t need to lock anything (all mouse and keyboard calls are operated by the simulators, and have no bearing on values controlled by the tertiary tab), I just need to be able to a) have the thread perform the same function whenever a user presses a button, and b) remove some of the excess materials.
I was also informed that ‘Thread.CurrentThread.Abort’ is threadsafe and therefore a fine way to end a thread if you wanted to end it forever, but if I can have the thread repeat its functions instead of killing it, that’d be wonderful…
To reuse the play thread, you could use an
AutoResetEventthat youSet()from the main thread. The same goes for when the thread is idle – the main thread prepares the data required to play, thenSet()s a differentAutoResetEvent, causing the play thread to start.So the
startPlayingAutoResetEventin below example causes the thread to wait until the main thread tells it to “go”, while thestopPlayingAutoResetEventcauses the play thread to respond to the main thread telling it to “stop” whenever it is not performing a step.Main thread:
Play thread: