How to reuse a thread in C# - c#

I wanted to know how to reuse a thread. I have a websocket connection that constantly sends messages which need some computation to be done. I want to add this computation to a thread, but don't want to create a new thread everytime. How can I make it so that the thread is reused?
client.MsgRecieved.Subscribe(info =>
{
Thread t = new Thread(() => Do_work(info));
};
Is there a way I can create a thread, name it and then just add Do_work() on that thread?
Edit:
I get multiple messages from the websocket per second. I rather have them wait in a single queue, rather than all run on a new thread.

The simplest pattern is simply
client.MsgRecieved.Subscribe(async info =>{
await Task.Run(Do_work(info));
});
Which queues the method to run on the built-in threadpool.
If you want to queue the messages to run on a single background thread, you can use a BlockingCollection, something like:
var workQueue = new System.Collections.Concurrent.BlockingCollection<Object>();
var workThread = new System.Threading.Thread(() =>
{
foreach (var work in workQueue.GetConsumingEnumerable())
{
Do_Work(work);
}
});
workThread.Start();
then
client.MsgRecieved.Subscribe(info => {
workQueue.Add(info);
};

Related

Is it possible to await Thread in C#

I am in a situation where I have to spawn a new thread manually, so I am able to can call .SetApartmentState(ApartmentState.STA). This means (as far as I know) that I cannot use Task. But I would like to know when the thread was done running, something like the await which works with async. However, the best I can come up with is a loop, constantly checking Thread.IsAlive, like this:
var thread = new Thread(() =>
{
// my code here
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while(thread.IsAlive)
{
// Wait 100 ms
Thread.Sleep(100);
}
This should work (as long as the thread don't end up stalling), but it seems kind of clumsy. Isn't there a more clever way to check when the thread is done (or dead)?
It is only to avoid blocking the GUI thread, so any minor performance hits are fine (like some hundred milliseconds).
Here is an extension method you could use to enable the awaiting of threads (inspired from this article: await anything).
public static TaskAwaiter GetAwaiter(this Thread thread)
{
return Task.Run(async () =>
{
while (thread.IsAlive)
{
await Task.Delay(100).ConfigureAwait(false);
}
}).GetAwaiter();
}
Usage example:
var thread = new Thread(() =>
{
Thread.Sleep(1000); // Simulate some background work
});
thread.IsBackground = true;
thread.Start();
await thread; // Wait asynchronously until the thread is completed
thread.Join(); // If you want to be extra sure that the thread has finished
Could you use the BackgroundWorker class? It has an event that reports when its finished.

Instantiating a Thread within a foreach loop in C#

I have a function that connects to a Multiple SQL server instances to fetch a set of data from each server for comparison of the data among multiple environments
I have a collection of the connection strings
I am calling this method in a foreach loop for each connection string in the collection
Since the data is fetched from different servers individually one at a time it takes up a lot of time
I would like to know if i use threads to call this method every time what would be the best way to do it?
There are a couple of ways to do this
1.) create a set of tasks and then do "await Task.WaitAll(listOfTasks)"
2.) Use Parallel.ForEach
3.) Manage threads
Managing threads
I do this in 2 steps:
1.) Create a list of threads
List<Thread> threads = new List<Thread>();
foreach(var connectionString in ConnectionStrings)
{
var thread = new Thread(DoWork);
thread.Start(connectionString);
threads.Add(thread);
}
2.) Join the threads to the current thread, has the effect of blocking until all are complete.
foreach(var thread in threads)
{
thread.Join()
}
You could Join the threads and make the program wait all of them until they are finished. It is a good pratice before moving to the next step. Look the code bellow with the comment, for sample:
// list of threads
List<Thread> threads = new List<Thread>();
// list of the results for each thread
List<SomeTypeDto> results = new List<SomeTypeDto>();
foreach(var connectionString in connectionStringList) {
// create the thread
Thread thread = new Thread(() => {
// access the database
SomeTypeDto result = /* process some result data*/;
lock (results) {
results.Add(result);
}
});
threads.Add(thread);
}
// start all threads
foreach (Thread thread in threads) {
thread.Start();
}
// Wait for all the threads to finish
foreach (Thread thread in threads) {
thread.Join();
}

Create IO bound observable with RX

I have a worker thread making blocking calls (ReadFrame)
to read incoming data from a socket (IO bound).
The thread runs a loop, that feeds the data into an Subject,
that can be observed by consumers.
private void ReadLoop()
{
while (!IsDisposed)
{
var frame = _Socket.ReadFrame();
_ReceivedFrames.OnNext(frame);
}
}
I wonder if there is a more RX kind of way to do this.
Here is an attempt (toy example) I made:
var src = Observable
.Repeat(Unit.Default)
.Select(_ =>
{
Thread.Sleep(1000); // simulated blocking ReadFrame call
return "data read from socket";
})
.SubscribeOn(ThreadPoolScheduler.Instance) // avoid blocking when subscribing
.ObserveOn(NewThreadScheduler.Default) // spin up new thread (?)
.Publish()
.RefCount();
var d = src.Subscribe(s => s.Dump()); // simulated consumer
Console.ReadLine(); // simulated main running code
d.Dispose(); // tear down
I'm struggling with the correct use of ObserveOn, SubscribeOn and the schedulers.
The toy example seems to work, but I'm not sure if the thread's lifetime is managed correctly.
Is the reader thread shut down with the d.Dispose() call?
Do I need to create a new thread at all?
Should I use Observable.Create instead? How?
Below additional info requested by #Enigmativity:
The ReadLoop() method is part of a class that conforms to the following interface:
public interface ICanSocket : IDisposable
{
IObservable<CanFrame> ReceivedFrames { get; }
IObserver<CanFrame> FramesToSend { get; }
}
Its member _Socket is disposed (closed) when the parent ICanSocket is disposed.
The most "Rxy" way to do this is to use Rxx, which has observable methods for doing async I/O.
Seems like your primary concerns are:
When subscribing, do not block the subscriber thread (aka run the I/O thread on a background thread)
When the caller unsubscribes, stop the I/O thread
One way to solve these is to just use the async Create method:
// just use Task.Run to "background" the work
var src = Observable
.Create<CanFrame>((observer, cancellationToken) => Task.Run(() =>
{
while (!cancellationToken.IsCancellationRequested)
{
var frame = _Socket.ReadFrame();
if (frame == null) // end of stream?
{
// will send a Completed event
return;
}
observer.OnNext(frame);
}
}));
var d = src.Subscribe(s => s.Dump());
Console.ReadLine();
d.Dispose();

Threading methods from other classes?

There is a method that is called continuously in my program and so I want to thread it such that the GUI doesn't freeze whilst it goes about its business.
Thread t = new Thread(Class2.ArrayWorkings(1, MyGlobals.variable1));
t.start();
int[] localVariable1 = ??// I want to move the value returned from the method into localVariable1.
Currently my errors are:
The best overloaded method match for 'System.Threading.Thread.Thread(System.Threading.ParameterizedThreadStart)' has some invalid arguments
&
Argument 1: cannot convert from 'method group' to 'System.Threading.ParameterizedThreadStart'
Currently doing this without threading like:
int[] localVariabl1 = Class2.ArrayWorkings(1, MyGlobals.variable1);
You can fix the constructor by using a lambda:
Thread t = new Thread(() => Class2.ArrayWorkings(1, MyGlobals.variable1));
but that doesn't let you (as Jon notes) get the result straight away - otherwise you are writing synchronous code again. You can instead look to some kind of callback; presumably you need to get back to the UI thread, so:
Thread t = new Thread(() => {
// this runs on the worker
int[] localVariabl1 = Class2.ArrayWorkings(1, MyGlobals.variable1);
this.Invoke((MethodInvoker)delegate {
// now we're back on the UI thread!
update the UI from localVariabl1
});
});
t.Start()
I would probably suggest using the thread-pool, though:
ThreadPool.QueueUserWorkItem(delegate {
// this runs on the worker
int[] localVariabl1 = Class2.ArrayWorkings(1, MyGlobals.variable1);
this.Invoke((MethodInvoker)delegate {
// now we're back on the UI thread!
update the UI from localVariabl1
});
});
You gotto put a ThreadStart Delegate. If you really dont want UI to get affected, u should use BackgroundWorker Class.
One way of doing it is as following:
ThreadStart starter = delegate { Class2.ArrayWorkings(1, MyGlobals.variable1); };
var thread = new Thread(starter);
thread.Start();
Edit: Just saw that you also want to capture the return value from the thread.
You may have to use ThreadPool.QueueUserWorkItem as mentioned in Marc's answer
Something you might want to look at is .NET Framework 4.5 (still in Release Candidate)
Makes life easier with Asynchronous programming.
await operator in .NET 4.5
Tasks provide an easy interface for performing an asynchronous job that will eventually return a value. A Task<string> for example is a task that (eventually) returns a string where a Task<int[]> will return an array of integers.
int[] localVariable1;
// start the task
Task<int[]> myTask = Task.Factory.StartNew<int[]>(() => Class2.ArrayWorkings(1, MyGlobals.Variable1);
// when it is finished get the result and place in local variable
myTask.OnCompleted(task => localVariable1 = task.Result;);
If you want to update a UI compontent once the asynchronous operation is finished, you will have to use Invoke (for winforms). This allows you to work with objects that live on the UI thread (such as buttons and labels).
myTask.OnCompleted(task => localVariable1.Invoke(new Action(() =>
localVariable1.Value = task.Result; )));

Task workflow sequence is wrong

With the code below, the final UI updates made in the final ContinueWith never take place. I think it is because of the Wait() I have at the end.
The reason I am doing that is because without the Wait, the method will return the IDataProvider before its finished being constructed in the background.
Can someone help me get this right?
Cheers,
Berryl
private IDataProvider _buildSQLiteProvider()
{
IDataProvider resultingDataProvider = null;
ISession session = null;
var watch = Stopwatch.StartNew();
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
// get the data
var buildProvider = Task.Factory
.StartNew(
() =>
{
// code to build it
});
// show some progress if we haven't finished
buildProvider.ContinueWith(
taskResult =>
{
// show we are making progress;
},
CancellationToken.None, TaskContinuationOptions.None, uiContext);
// we have data: reflect completed status in ui
buildProvider.ContinueWith(
dataProvider =>
{
// show we are finished;
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiContext);
try {
buildProvider.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
Console.WriteLine(e.Message);
}
Console.WriteLine("Exception handled. Let's move on.");
CurrentSessionContext.Bind(session);
return resultingDataProvider;
}
====
just to be clear
I am not having trouble talking to the ui thread. The first continue with updates the ui just fine. The trouble I am having is the timing of the last ui update and the return of the data provider.
I commented out some of the code to reduce the noise level in tis post and focus on the task sequencing.
====
ok, working code
private void _showSQLiteProjecPicker()
{
var watch = Stopwatch.StartNew();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
ISession session = null;
// get the data
var buildProvider = Task.Factory.StartNew(
() =>
{
var setProgress = Task.Factory.StartNew(
() =>
{
IsBusy = true;
Status = string.Format("Fetching data...");
},
CancellationToken.None, TaskCreationOptions.None, uiScheduler);
var provider = new SQLiteDataProvider();
session = SQLiteDataProvider.Session;
return provider;
});
buildProvider.ContinueWith(
buildTask =>
{
if(buildTask.Exception != null) {
Console.WriteLine(buildTask.Exception);
}
else {
Check.RequireNotNull(buildTask.Result);
Check.RequireNotNull(session);
_updateUiTaskIsComplete(watch);
CurrentSessionContext.Bind(session);
var provider = buildTask.Result;
var dao = provider.GetActivitySubjectDao();
var vm = new ProjectPickerViewModel(dao);
_showPicker(vm);
}
},
CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiScheduler);
}
UPDATE BELOW
This code doesn't look like it warrants TPL to me. Looks like maybe a good use for a BackgroundWorker instead!
Either way, the updates are probably not taking place because you can't update the UI from a separate thread -- you need to run the update on the UI thread. You should use the Dispatcher for this (http://stackoverflow.com/questions/303116/system-windows-threading-dispatcher-and-winforms contains info for both WPF and WinForms)
Update:
So I obviously missed some of the code so here's a revised answer. First of all, Nicholas is correct -- .ContinueWith returns a new task (http://msdn.microsoft.com/en-us/library/dd270696.aspx). So instead of
var result = Task.Factory.StartNew(...);
result.ContinueWith(...);
you probably want to create a new task and then make all the ContinueWith() calls and assign to the task and then call .Start() on the task. Something like:
var task = new Task(...).ContinueWith(...);
task.Start();
However, there is a flaw in the design to begin with (as I see it)! You're trying to run this code async, wihch is why you're using threads and TPL. However, you're calling buildProvider.Wait(); on the UI thread which blocks the UI thread until this task completes! Aside from the issue of repainting the UI in the ContinueWith() while the UI thread is blocked, there's no benefit to multithreading here since you're blocking the UI thread (a major no-no). What you probably want to do is stick the Bind()-ing inside a ContinueWith or something so that you don't have to call Wait() and block the UI thread.
My $0.02 is that if you expect the query to take a long time what you really want is 2 threads (or tasks in TPL)-- one to perform the query and one to update the UI at intervals with status. If you don't expect it to take so long I think you just want a single thread (Task) to query and then update the UI when it's done. I would probably do this via BackgroundWorker. TPL was built for managing lots of tasks and continuations and such but seems overkill for this kind of thing -- I think you could do it using a BackgroundWorker in a lot less code. But you mention you want to use TPL which is fine, but you're going to have to rework this a bit so that it actually runs in the background!
PS - you probably meant to put the Console.WriteLine("Exception handled. Let's move on."); inside the catch
I'm a little hazy, but last time I used the TPL I found it confusing. ContinueWith() returns a new Task instance. So you need to assign the second ContinueWith() result to a new variable, say var continuedTask = builderProvider.ContinueWith(...), and then change the last one to reference continuedTask.ContinueWith() instead of buildProvider.ContinueWith(). Then Wait() on the last Task.
Hope that helps!

Categories