Worker Threads in C#

來源:互聯網
上載者:User
[原文]

Introduction

The .NET framework provides a lot of ways to implement multithreading programs. I want
to show how we can run a worker thread which makes syncronous calls to a user
interface (for example, a thread that reads a long recordset and fills some control
in the form).

To run thread I use:

  • Thread instance and main thread function
  • Two events used to stop thread. First event is set when main thread wants
    to stop worker thread; second event is set by worker thread when it really
    stops.

.NET allows you to call System.Windows.Forms.Control functions only from the thread
in which the control was created. To run them from another thread we need to use the
Control.Invoke (synchronous call) or Control.BeginInvoke (asynchronous call)
functions. For tasks like showing database records we need Invoke.

To implement this we will use:

  • A Delegate type for calling the form function. Delegate instance and function called using this delegate
  • The Invoke call from the worker thread.

The next problem is to stop the worker thread correctly. The steps to do this are:

  • Set the event "Stop Thread"
  • Wait for the event "Thread is stopped"
  • Wait for the event process messages using the Application.DoEvents
    function. This prevents deadlocks because the worker thread makes Invoke calls
    which are processed in the main thread.

The thread function checks every iteration whether the "Stop Thread" event has been set.
If the event is set the function invokes clean-up operations, sets the event "Thread is
stopped" and returns.

Demo project has two classes: MainForm and LongProcess. The LongProcess.Run
function runs in a thread and fills the list box with some lines. The worker thread
may finish naturally or may be stopped when user presses the "Stop Thread"
button or closes the form.

Code fragments Collapse
// MainForm.cs

namespace WorkerThread
{
// delegates used to call MainForm functions from worker thread
public delegate void DelegateAddString(String s);
public delegate void DelegateThreadFinished();

public class MainForm : System.Windows.Forms.Form
{
// ...

// worker thread
Thread m_WorkerThread;

// events used to stop worker thread
ManualResetEvent m_EventStopThread;
ManualResetEvent m_EventThreadStopped;

// Delegate instances used to call user interface functions
// from worker thread:
public DelegateAddString m_DelegateAddString;
public DelegateThreadFinished m_DelegateThreadFinished;

// ...

public MainForm()
{
InitializeComponent();

// initialize delegates
m_DelegateAddString = new DelegateAddString(this.AddString);
m_DelegateThreadFinished = new DelegateThreadFinished(this.ThreadFinished);

// initialize events
m_EventStopThread = new ManualResetEvent(false);
m_EventThreadStopped = new ManualResetEvent(false);

}

// ...

// Start thread button is pressed
private void btnStartThread_Click(object sender, System.EventArgs e)
{
// ...

// reset events
m_EventStopThread.Reset();
m_EventThreadStopped.Reset();

// create worker thread instance
m_WorkerThread = new Thread(new ThreadStart(this.WorkerThreadFunction));

m_WorkerThread.Name = "Worker Thread Sample"; // looks nice in Output window

m_WorkerThread.Start();

}


// Worker thread function.
// Called indirectly from btnStartThread_Click
private void WorkerThreadFunction()
{
LongProcess longProcess;

longProcess = new LongProcess(m_EventStopThread, m_EventThreadStopped, this);

longProcess.Run();
}

// Stop worker thread if it is running.
// Called when user presses Stop button or form is closed.
private void StopThread()
{
if ( m_WorkerThread != null && m_WorkerThread.IsAlive ) // thread is active
{
// set event "Stop"
m_EventStopThread.Set();

// wait when thread will stop or finish
while (m_WorkerThread.IsAlive)
{
// We cannot use here infinite wait because our thread
// makes syncronous calls to main form, this will cause deadlock.
// Instead of this we wait for event some appropriate time
// (and by the way give time to worker thread) and
// process events. These events may contain Invoke calls.
if ( WaitHandle.WaitAll(
(new ManualResetEvent[] {m_EventThreadStopped}),
100,
true) )
{
break;
}

Application.DoEvents();
}
}
}

// Add string to list box.
// Called from worker thread using delegate and Control.Invoke
private void AddString(String s)
{
listBox1.Items.Add(s);
}

// Set initial state of controls.
// Called from worker thread using delegate and Control.Invoke
private void ThreadFinished()
{
btnStartThread.Enabled = true;
btnStopThread.Enabled = false;
}

}
}

// LongProcess.cs

namespace WorkerThread
{
public class LongProcess
{
// ...

// Function runs in worker thread and emulates long process.
public void Run()
{
int i;
String s;

for (i = 1; i <= 10; i++)
{
// make step
s = "Step number " + i.ToString() + " executed";

Thread.Sleep(400);

// Make synchronous call to main form.
// MainForm.AddString function runs in main thread.
// (To make asynchronous call use BeginInvoke)
m_form.Invoke(m_form.m_DelegateAddString, new Object[] {s});


// check if thread is cancelled
if ( m_EventStop.WaitOne(0, true) )
{
// clean-up operations may be placed here
// ...

// inform main thread that this thread stopped
m_EventStopped.Set();

return;
}
}

// Make synchronous call to main form
// to inform it that thread finished
m_form.Invoke(m_form.m_DelegateThreadFinished, null);
}

}
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.