2

I have a GUI and only 1 background thread (constantly running). The GUI must be able to tell the bg thread to do some actions in between its work. Just like a GUI thread can do work when it's idling. I know normal threads aren't idling. Nevertheless I need to know: what are the possibilities here?

Changing to a GUI thread is simple when you have a control:

if (InvokeRequired)
    this.Invoke(new Action<string>(thisMethod), new object[] { text });
else
{
    // ...
}

Now - when the user clicks a button - how do I execute a method on a background thread that is already running? By background threads I'm referring to these guys:

  • new Thread(new ThreadStart(MyThread.Run)).Start();
  • ThreadPool.QueueUserWorkItem(o => { MyThread.Run(); });

I'm interested in both: Invoke- and BeginInvoke-style.

Thanks for the help!

Bitterblue
  • 13,162
  • 17
  • 86
  • 124
  • 1
    `Task.Run( () => { })` – Callum Linington Mar 04 '15 at 10:15
  • You should almost never use `new Thread`. Stick to the threadpool, threads are VERY expensive to create. – Aron Mar 04 '15 at 10:50
  • 1
    Running code on a *specific* thread is not possible unless the target thread co-operates. It has to solve the [producer-consumer problem](https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem). Whose universal solution is a thread-safe queue and a dispatcher loop that retrieves invocation requests from that queue. Maybe that starts to sound familiar, yes, that's how a GUI thread operates. Well supported in .NET of course. You like BeginInvoke(), you [might as well use it](http://stackoverflow.com/a/21684059/17034). – Hans Passant Mar 04 '15 at 11:02

2 Answers2

3

Create a queue that is peeked at by the background thread. If there is an object in the queue, do the work for that object otherwise do (a part of) its own work.

Have the GUI thread put work in the queue.

Make sure the queue is thread-safe

Emond
  • 50,210
  • 11
  • 84
  • 115
1

You could use

public void test()
{
    ThreadPool.QueueUserWorkItem(_ => Background("test"));
}

or you couls use

public void test()
{
    Parallel.Invoke(() => Background("test"));
}

or like this

public void test()
{
    BackgroundDelegate c = new BackgroundMethodDelegate(Background);
    IAsyncResult a = c.BeginInvoke("test", null, null);
    c.EndInvoke(a);
}

or like this

public void test()
{
    Thread thread = new Thread(_ => Background("test"));
    thread.Start();
    thread.Join();
}

There are a lot of different ways to do this

EDIT:

The easiest way would be to use a background worker

var bw = new BackgroundWorker();            
bw.DoWork += (worker, args) => {
    Background("test");
};
bw.RunWorkerAsync();

In that case you can easily reuse the background worker

you can even add a queue to it if needed Creating BackgroundWorker with Queue

Community
  • 1
  • 1
Owain van Brakel
  • 3,109
  • 1
  • 15
  • 22
  • I might have asked ambiguously, please see my edit. Sorry. I don't want to spawn threads. I have one background thread and I *need* to reuse it. – Bitterblue Mar 04 '15 at 10:27
  • @Bitterblue you mean you want some kind of a "pool" of "thread(s)", which allows you to reuse the "thread(s)" inside it? I think you might want to implement a `ThreadPool`. – Aron Mar 04 '15 at 10:52
  • @Aron No, I have only **one** background thread. I don't want to reset it. I want to "squeeze in" operations into it's work. – Bitterblue Mar 04 '15 at 10:59