Sorry for my bad English. Hope someone suggests me a better version of my question.
I've searched but seemed like I couldn't find the answer for my problem.
Currently, I'm writing a C# WPF app. This app will perform a heavy task in a long time. So I've decided to create another class with that heavy method and pass that method to another thread. I have to create a class to do that because the heavy method takes parameters.
I want the ability to suspend and resume that thread. I've known that I should use a ManualResetEvent object or Thread.Sleep method.
After many hours of trying and testing, getting confused why I always end up suspend the UI thread but the heavy thread is still running. What I've tried were:
Create a ManualResetEvent object called mre inside the HeavyClass. When user click the Pause button, the UI class will call the method heavyClass.mre.WaitOne().
class HeavyClass
{
// properties
ManualResetEvent mre = new ManualResetEvent(false);
public void HeavyRun()
{
//Do something takes really long time
//And doesn't have any loops
}
}
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
heavyClass.mre.WaitOne();
}
}
Create a method called SleepThread inside the HeavyClass. When user click the Pause button, the UI class will call the method heavyClass.SleepThread().
class HeavyClass
{
//properties
ManualResetEvent mre = new ManualResetEvent(false);
public void SleepThread()
{
Thread.Sleep(Timeout.Infinite);
//mre.WaitOne();
//They are the same behavior
}
public void HeavyRun()
{
//Do something takes really long time
//And doesn't have any loops
}
}
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
heavyClass.SleepThread();
}
}
Create an EventHandler<MainWindow> PauseThread inside the UI class, then write its handle inside the HeavyClass. When user click the Pause button, the UI class will trigger the event PauseThread(this, this).
class MainWindow : Window
{
// properties
private HeavyClass heavyClass = new HeavyClass();
public event EventHandler<MainWindow> PauseThread;
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun);
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
PauseThread(this, this);
}
}
class HeavyClass
{
// properties
ManualResetEvent mre = new ManualResetEvent(false);
public void HeavyRun()
{
MainWindow.PauseThread += (s, E) =>
{
Thread.Sleep(Timeout.Infinite);
//mre.WaitOne();
//They are the same behavior
};
//Do something takes really long time
//And doesn't have any loops
}
}
As I said above, I always paused the UI thread and the heavy task is still running.
And finally in the end, I've known the essence of my problem. That is: which thread calls Thread.Sleep() or WaitOne() will be blocked. Yeah, "which thread", not "which class".
Everything makes sense for me now. But that doesn't help me to achieve my goal. And that leads me to think that I am doing the seemingly impossible thing. It's clearly that I want to pause a thread by another thread. But that another thread is the one who calls any kinds of "suspend thread", so it is the one who is suspended. I don't have any idea about how to make the heavy method to be suspended by itself. It is running, how the hell it could know when the user click the Pause button?
I am at a total loss. Someone please help me to make my app works as expected.
By the way, this impossible thing makes me think that I am doing things wrong way, is it?
UPDATE: If you like to see my heavy task, actually it is very simple
class HeavyClass
{
public string filePath = "D:\\Desktop\\bigfile.iso";//This file is about 10GB
public string HeavyRun()
{
string MD5Hash;
MD5 md5 = MD5.Create();
Stream stream = File.OpenRead(filePath);
MD5Hash = Encoding.Default.GetString(md5.ComputeHash(stream));
return MD5Hash;
}
}
To make a thread suspendable, the work in the thread must be separable. In your case md5.ComputeHash(stream) will do all the work, and there is not way to make sure that thread will suspend at a right(saft) point inside md5.ComputeHash(stream). So you have to rewrite HeavyClass like below. Please notice that those codes are not the best approach of handling a thread, and I just try to keep it as same as the original.
class HeavyClass
{
MD5 _md5 = MD5.Create();
MethodInfo _hashCoreMI = _md5.GetType().GetMethod("HashCore", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo _HashFinalMI = _md5.GetType().GetMethod("HashFinal", BindingFlags.NonPublic | BindingFlags.Instance);
WaitHandle _signal;
public void HeavyClass(WaitHandle signal)
{
_signal = signal;
}
public string HeavyRun(string filename)
{
byte[] buffer = new byte[4096];
int bytesRead = 0;
_signal.Set();
using(FileStream fs = File.OpenRead(filename))
{
while(true)
{
bytesRead = fs.Read(buffer, 0, 4096);
if (bytesRead > 0)
{
_hashCoreMI.Invoke(_md5, new object[] { buffer, 0, bytesRead });
}
else
{
break;
}
// if WaitHandle is signalled, thread will be block,
// otherwise thread will keep running.
_signal.WaitOne();
}
}
byte[] hash = _hashFinalMI.Invoke(_md5, null);
_md5.Initialize();
return Encoding.ASCII.GetString(hash);;
}
}
class MainWindow : Window
{
private HeavyClass _heavyClass;
private ManualResetEvent _mre;
public MainWindow()
{
InitializeComponent();
_mre = new ManualResetEvent(true);
_heavyClass = new HeavyClass(_mer);
}
private void buttonStart_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(heavyClass.HeavyRun("D:\\Desktop\\bigfile.iso"));
t.Start();
}
private void buttonPause_Click(object sender, RoutedEventArgs e)
{
_mre.Reset();
}
private void buttonResume_Click(object sender, RoutedEventArgs e)
{
_mre.Set();
}
}
Related
I want to start / stop a thread in order not to block the UI using button
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
//What i had tried
//_canceller.Dispose();
//_canceller.Cancel();
// varriablesStatus = false;
//thread2.break;
//autoResetEvent.WaitOne();
//thread2.Join();
//_manualResetEvent.Reset();
//thread2.Abort();
//_pauseEvent.Reset();
//varriablesStatus = "Pause";
//Print_Actions();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW,
TextBox Status, ProgressBar Progress, bool varriablesStatus)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
}
}
}
}
How can I start stop pause resume the thread because nothing worked from what I had tried, I think the problem is from the foreach loop
I never used threads, and I can not find an example similar with mine in order to understand how should I do.
What you are asking implies that you want to use the Thread.Suspend and Thread.Resume methods. Possibly like this:
private volatile Thread _printThread;
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
_printThread = Thread.CurrentThread;
try
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1,
varriablesStatus);
}
finally { _printThread = null; }
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
var printThread = _printThread;
if (printThread != null)
{
if (printThread.ThreadState.HasFlag(ThreadState.Running))
{
printThread.Suspend();
}
else if (printThread.ThreadState.HasFlag(ThreadState.Suspended))
{
printThread.Resume();
}
}
}
The documentation of these two methods includes several cautionary warnings that discourage usage:
Thread.Suspend has been deprecated. Use other classes in System.Threading, such as Monitor, Mutex, Event, and Semaphore, to synchronize Threads or protect resources.
Do not use the Suspend and Resume methods to synchronize the activities of threads. You have no way of knowing what code a thread is executing when you suspend it. If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. Deadlocks can occur very easily.
It's up to you if you want to accept these risks. If you ask me, you shouldn't.
Note: The Suspend and Resume methods are not supported on .NET Core and later platforms. On these platforms they throw a PlatformNotSupportedException exception. You can use them only if you target the .NET Framework platform.
i made this work, i do not know if it is the right way but for the moment it works
public partial class Program_Form : Form
{
readonly BackgroundWorker m_oWorker;
CancellationTokenSource _tokenSource = null;
[STAThread]
private void Program_Form_Load(object sender, EventArgs e)
{
// long code here
}
private async void DGW6BtnPrint_Click(object sender, EventArgs e)
{
_tokenSource = new CancellationTokenSource();
var token = _tokenSource.Token;
Work.Printer_ Print = new Work.Printer_();
await Task.Run(() =>
{
Print.Print_File(this, dataGridView6, StatusText, progressBar1, token);
});
}
public void BTN6PPauza_Click(object sender, EventArgs e)
{
_tokenSource.Cancel();
}
}
Referenced class:
namespace OfficeTools.Work
{
class Printer_
{
public void Print_File(Program_Form callForm, DataGridView DGW, TextBox Status, ProgressBar Progress, CancellationToken Token)
{
foreach (DataGridViewRow Row in DGW.Rows)
{
file = DGW.Rows[Row.Index].Cells[4].Value.ToString();
PrintFiles.Print_Word(file);
if (Token.IsCancellationRequested)
{
try
{
Winword.Quit(ref missing, ref missing, ref missing);
winword = null;
}
catch { }
return;
}
}
}
}
}
Kind regards all
I made a thread at load event like below:
Thread checkAlert = null;
bool isStop = false;
private void frmMain_Load(object sender, EventArgs e)
{
checkAlert = new Thread(CheckAlert);
checkAlert.Start();
}
void CheckAlert()
{
while (!isStop)
{
Thread.Sleep(60000);
//do work here
}
}
Is there any way to resume the checkAlert thread during it's sleep period?( Thread.Sleep(60000);)
I tried using Thread.Interrupt() but it flows a ThreadInterruptedException, how should I handle this exception? or is there any way to resume the thread?
Edited:
I need to wake up the thread before the "sleep" end because when the user wants to quit the program, the program will have to wait for some time before it really quits ( checkAlert is still running) Is there any way to improve this case?
Based on your comments what it looks like is you need to re-design how CheckAlert works so it does not use Sleep's at all. What you should be doing is using a Timer instead.
System.Timers.Timer timer = null;
public FrmMain()
{
InitializeComponent();
timer = new System.Timers.Timer(60000);
timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
//If you want OnTimedEvent to happen on the UI thread instead of a ThreadPool thread, uncomment the following line.
//timer.SynchronizingObject = this;
if(this.components == null)
this.components = new System.ComponentModel.Container();
//This makes it so when the form is disposed the timer will be disposed with it.
this.componets.Add(timer);
}
private void frmMain_Load(object sender, EventArgs e)
{
timer.Start();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
//It is good practice not to do complicated logic in a event handler
// if we move the logic to its own method it is much easier to test (you are writing unit tests, right? ;) )
CheckAlert();
}
void CheckAlert()
{
//do work here
}
private void frmMain_Close(object sender, EventArgs e)
{
timer.Stop();
}
If you want the thread to exit automatically when your program quits, simply make it a background thread.
checkAlert = new Thread(CheckAlert);
checkAlert.IsBackground = true;
checkAlert.Start();
It looks to me like you're trying to create a thread which handles two types of events: do something and stop running.
Rather than using a shared variable (isStop) and some other technique to interrupt the thread in order to do work, you might want to use threading events (not to be confused high-level UI Event objects) to control your thread.
AutoResetEvent stop = new AutoResetEvent(false);
AutoResetEvent check = new AutoResetEvent(false);
private void CheckAlert() {
WaitHandle[] handles = new WaitHandle[] { stop, check };
for (;;) {
switch (AutoResetEvent.WaitAny(handles)) {
case 0:
return;
case 1:
// do work
break;
}
}
}
Calling check.Set() in your code will trigger the "do work" branch in the thread and stop.Set() will cause the thread to terminate gracefully.
Once your code has called stop.Set() to terminate the thread, it can call the thread's Join() method to wait until the thread terminates.
EDIT
I misunderstood the question. I will leave the code above in case anyone finds it useful.
If all you want to do is have a thread that performs a task once a minute and stop on demand, you can use the following code:
AutoResetEvent stop = new AutoResetEvent(false);
void CheckAlert() {
var time = new TimeSpan(0, 1, 0); // one minute
while (!stop.WaitOne(time)) {
// do work
}
}
private Thread checkThread;
private void frmMain_Load(object sender, EventArgs e) {
checkThread = new Thread(CheckAlert);
checkThread.Start();
}
private void frmMain_Close(object sender, EventArgs e) {
stop.Set(); // signal thread to stop
checkThread.Join(); // wait for thread to terminate
}
You can see an explanation on how to wake a sleeping thread here:
https://msdn.microsoft.com/en-us/library/tttdef8x%28v=vs.100%29.aspx
and this is a complete example (as you can see, Thread.Interrupt is the good choise... however you have to catch it to continue normal thread execution):
public class HVCSensor : HVCDevice, IDisposable
{
private Thread myThread;
private const int execute_timeout = ((10 + 10 + 6 + 3 + 15 + 15 + 1 + 1 + 15 + 10) * 1000);
private bool disposed = false;
private bool paused = false;
public delegate void HVCResultsHandler(HVC_RESULT res);
public event HVCResultsHandler HVCResultsArrived;
private void OnHVCResultsArrived(HVC_RESULT res)
{
if (HVCResultsArrived != null) {
HVCResultsArrived(res);
}
}
public HVCSensor() {
myThread = new Thread(new ThreadStart(this.execute));
}
private void execute(){
while (!disposed) {
if (!paused && this.IsConnected)
{
HVC_RESULT outRes;
byte status;
try
{
this.ExecuteEx(execute_timeout, activeDetections, imageAcquire, out outRes, out status);
OnHVCResultsArrived(outRes);
}
catch (Exception ex) {
}
}
else {
try
{
Thread.Sleep(1000);
}
catch (ThreadInterruptedException e)
{
}
}
}
}
public HVC_EXECUTION_IMAGE imageAcquire
{
get;
set;
}
public HVC_EXECUTION_FLAG activeDetections
{
get;
set;
}
public void startDetection() {
if(myThread.ThreadState==ThreadState.Unstarted)
myThread.Start();
}
public void pauseDetection() {
paused = true;
}
public void resumeDetection() {
paused = false;
if (myThread.ThreadState == ThreadState.WaitSleepJoin)
myThread.Interrupt();
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
disposed = true;
myThread.Interrupt();
}
}
I have a c++/cli wrapper class which grabs frames from a camera and sends them as events.
A WPF test application Starts the camera, and updates the images.
When I click Stop, it usually ends in a deadlock, on m->streamThread->Join(). I'm suspecting the problem has to do with the frame handling event in the WPF, rather than the wrapper code.
namespace WpfTestApp
{
public partial class Window1 : Window
{
private void OnFrameArrived(object sender, EventArgs e)
{
Action a = delegate
{
// this uses Imaging.CreateBitmapSourceFromMemorySection
// to copy the frame data to the image memory
m_colorImage.UpdateImage(e.Image);
};
Dispatcher.Invoke(a);
}
private void startBtn_Click(object sender, RoutedEventArgs e)
{
m_camera.FrameArrived += m_frameHandler;
m_camera.Start();
}
private void Stop()
{
m_camera.FrameArrived -= m_frameHandler;
m_camera.Stop();
}
}
}
// Camera.h
public ref class Camera
{
public:
delegate void FrameArrivedHandler(Object^ sender, DGEventArgs^ e);
event FrameArrivedHandler^ FrameArrived;
void Start();
void Stop();
private:
void StreamThreadWorker();
Thread^ m_streamThread;
bool m_isStreaming;
}
// Camera.cpp
void Camera::Start()
{
if (m_isStreaming)
return;
m_isStreaming = true;
m_streamThread = gcnew Thread(gcnew ThreadStart(this, &Camera::StreamThreadWorker));
m_streamThread->Start();
}
void Camera::Stop()
{
if (!m_isStreaming)
return;
m_isStreaming = false;
m_streamThread->Join(); // stuck here
}
void Camera::StreamThreadWorker()
{
EventArgs^ eventArgs = gcnew EventArgs();
while (m_isStreaming)
{
eventArgs->Image = Camera->GetImage();
FrameArrived(this, eventArgs);
}
}
likely what happens is: you click Stop, this gets handled in the WPF ui dispatcher thread. So the Join call is in the ui dispatcher thread. However this same thread is also responsible for drawing the frames (the invoked call to UpdateImage). As a result, the StreamThreadWorker is waiting on FrameArrived to finish, but that cannot finish because the thread is waiting for Stop to finish. There's your deadlock.
So in order to get the StreamThreadWorker to finish, it must not be blocked by Stop. An easy way to achive this is to stop the thread from within another thread:
void Camera::Stop()
{
...
gcnew Thread( gcnew ThreadStart( this, &Camera::DoStopThread ) )->Start();
}
void Camera::DoStopThread()
{
if( !m_streamThread.Join( 3000 ) )
HandleThreadDidNotStopInTimeError(); //notify listeners there's a serious problem
m_streamThread.Abort();
m_streamThread = null;
RaiseThreadStoppedEvent(); //notify listeners that the thread stopped
}
I am doing a practise GUI Oven program using a thread, I am not sure if I should even be doing this because I want to interact with the GUI when the Heating process is ongoing. When I try to abort the thread by click btnStop_Click, it throws the NullReference exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Please advice on how can I gracefully stop the thread. Thanks.
Code:
public partial class Form1 : Form
{
private Thread t;
public Form1()
{
InitializeComponent();
}
// button to begin heating
private void btnStart_Click(object sender, EventArgs e)
{
if ((txtMin.Text) == "" || (txtSec.Text) == "")
{
MessageBox.Show("Please enter duration of heating");
}
else
{
t = new Thread(heatIt);
btnHeat.Enabled = false;
t.Start();
}
}
//stop heating
private void btnStop_Click(object sender, EventArgs e)
{
Heating heat = new Heating();
Form1 l = new Form1();
l.Subscribe(heat);
heat.stopHeat();
btnHeat.Enabled = true;
}
private void heatIt()
{
// heat food Implementation that calls the 'Heating' class
}
public void Subscribe(Heating m)
{
m.heatComplete += SignalHeatCompleted;
m.heatStop += SignalStop;
}
private void SignalHeatCompleted(Heating m, EventArgs e)
{
MessageBox.Show( "Done, please enjoy your food");
return;
}
private void SignalStop(Heating m, EventArgs e)
{
t.Abort();
MessageBox.Show("Heating Terminated");
return;
}
public class Heating
{
public event HeatingCompleted heatComplete; // Heating Completed Event
public event HeatingStop heatStop; // Heating Stop Event
public EventArgs e = null;
public delegate void HeatingCompleted(Heating h, EventArgs e);
public delegate void HeatingStop(Heating s, EventArgs e);
public void startHeat(int temp, int min, int sec)
{
int totalSec;
totalSec = ((min*60) + sec) * 1000;
Thread.Sleep(totalSec);
if (heatComplete != null)
{
heatComplete(this, e);
}
else
{
//Use default signal if there's no subscription to this event
MessageBox.Show("*TING*");
}
return;
}
public void stopHeat()
{
if (heatStop != null)
{
heatStop(this, e);
}
}
}
}
You are creating a new instance of Form1 in your stop click event and so you are talking to a completely different t from the one in your start click.
You also probably want to have a single instance of Heat that you assign in heatIt and then use that reference in your stop click.
Also for background processing you probably want to look at the BackgroundWorker class to do the heavy lifting for you.
Several remarks:
You should never use Thread.Abort to stop background tasks. This is a bad practice, as it forces aborting the background thread regardless of its state. Use a volatile bool flag instead, and check (every once in a while) if its value has changed.
It seems that your Form represents a UI for business logic extracted into a separate class (Heating). In that case, it probably makes sense to have only a single instance per form, and put it in a private field. Right now you are creating a new instance inside your Stop method, which is probably wrong (since I presume you already use it in the heatIt method).
For each Subscribe method, try to keep a habit of adding a Unsubscribe method, which detaches event handlers at some point. This way GC can collect your listeners after they are no longer needed, and you prevent adding the same event handlers several times.
I would expect something like:
private Heating _heating;
private Thread _workerThread;
private volatile bool _stopRequest = false;
void Start_Btn_Pressed(object sender, EventArgs e)
{
// create the private instance
_heating = new Heating();
Subscribe(_heating);
// start the thread
_stopRequest = false;
_workerThread = new Thread(HeatIt);
_workerThread.Start();
}
void Stop_Btn_Pressed(object sender, EventArgs e)
{
// request stop
_stopRequest = true;
// wait until thread is finished
_workerThread.Join();
// unsubscribe
// ** note that a better place for unsubscribing
// might be at the end of the HeatIt method
Unsubscribe(_heating);
}
And, in your background worker method, you will need to have a loop which checks if _stopRequest has been set:
void HeatIt()
{
while (!_stopRequest && !finishedWork)
{
// do work
}
}
Note that you must have a place in your worker method which will check the _stopRequest flag. Otherwise the only way to stop it is to Abort it (like you did), which is not recommended.
Apart from that, you don't need to stop the thread (like you did in your SignalStop method) once the process is finished. When HeatIt method returns (ends), the thread will also end, and there is no need to do this.
I have a Windows Forms application at the moment, and I want to create a new thread and run a method on another class that accepts an input.
For example
public partial class Form1: Form {
SerialPort serialInput;
// I want to create a new thread that will pass the parameter serialInput into the method
// SMSListener on another class and run the method contionously on the background.
}
class SMS
{
public void SMSListener(SerialPort serial1)
{
serial1.DataReceived += port_DataRecieved;
}
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
// Other codes
}
}
How do I perform this in C#? I have seen numerous examples on the web, and most of them run the method on the same class with no parameters, but none that suits my requirements.
Perhaps a Background Worker could help you?
It is a bit hard to understand what you are aiming at.
public class Runner
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
public Runner()
{
_worker.DoWork += WorkerDoWork;
}
public void RunMe(int payload)
{
_worker.RunWorkerAsync(payload);
}
static void WorkerDoWork(object sender, DoWorkEventArgs e)
{
var worker = sender as BackgroundWorker;
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
break;
}
// Work
System.Threading.Thread.Sleep((int)e.Argument);
}
}
}
I am not an expert on Multithreading but to the best of my knowledge you can only start threads on methods that accept an object parameter and return void. So in order to achieve that for your problem (don't shoot me down if there is a better approach!) I would do something like
public partial class Form1: Form {
SerialPort serialInput;
// I want to create a new thread that will pass the parameter serialInput into the method
// SMSListener on another class and run the method contionously on the background.
SMS sms = new SMS();
Thread t = new Thread(sms.SMSListenerUntyped);
t.Start(serialInput);
}
class SMS
{
public void SMSListenerUntyped(object serial1) {
if (serial1 is SerialPort) //Check if the parameter is correctly typed.
this.SMSListener(serial1 as SerialPort);
else
throw new ArgumentException();
}
public void SMSListener(SerialPort serial1)
{
serial1.DataReceived += port_DataRecieved;
}
private void port_DataRecieved(object sender, SerialDataReceivedEventArgs e)
{
// Other code.
}
How about just use the ThreadPool directly with a anonymous method allowing you to access your surrounding locals?
public void OnButtonClick(object sender, EventArgs e)
{
SerialPort serialInput = this.SerialInput;
System.Threading.ThreadPool.QueueUserWorkItem(delegate
{
SmsListener listener = new SmsListener(serialInput);
});
}