Unit testing background threads - c#

How do you test background threads like this?
As the fetching of the kinect sensor could be a very time-consuming task. I create a task that calls Parallel to fetch the two things-kinect sensor and mcu. If either one is done, the UI will change the string (for both could be done first). It seems really hard to test for you cannot create a new kinectsensor, you can just get one from the KinectSensor.KinectSensors, I tried to simulate the delay so that I can check if the string has changed.
private void Initialize()
{
Task.Factory.StartNew(() =>
{
Parallel.Invoke(() =>
{
KinectSensor kinectSensor = null;
// while haven't got the sensor, keep fetching
while (kinectSensor == null)
{
Thread.Sleep(200);
kinectSensor = (from sensor in KinectSensor.KinectSensors
where sensor.Status == KinectStatus.Connected
select sensor).FirstOrDefault();
}
_kinectService = new KinectService(kinectSensor);
_kinectService.SetupKinectSensor(new EventHandler<ColorImageFrameReadyEventArgs>(ColorImageFrameReadyEventHandler),
new EventHandler<SkeletonFrameReadyEventArgs>(SkeletonFrameReadyEventHandler));
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
StatusDescription = "Kinect Has connected";
});
}, () =>
{
IMCU mcu = null;
while (mcu == null)
{
Thread.Sleep(200);
// get mcu here
}
_mcuService = new MCUService(mcu);
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
StatusDescription = "MCU Has connected";
});
});
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
CameraShadowColor = "#FF66B034";
StatusColor = "#FF66B034";
StatusCaption = "Ready";
StatusDescription = "Ready to go";
ButtonString = "OK";
});
});
}

Related

Alternatives for Monitor (Wait, PluseAll) in Async Tasks in C#

I implemented Task synchronization using Monitor in C#.
However, I have read Monitor should not be used in asynchronous operation.
In the below code, how do I implement Monitor methods Wait and PulseAll with a construct that works with Task (asynchronous operations).
I have read that SemaphoreSlim.WaitAsync and Release methods can help.
But how do they fit in the below sample where multiple tasks need to wait on a lock object, and releasing the lock wakes up all waiting tasks ?
private bool m_condition = false;
private readonly Object m_lock = new Object();
private async Task<bool> SyncInteralWithPoolingAsync(
SyncDatabase db,
List<EntryUpdateInfo> updateList)
{
List<Task> activeTasks = new List<Task>();
int addedTasks = 0;
int removedTasks = 0;
foreach (EntryUpdateInfo entryUpdateInfo in updateList)
{
Monitor.Enter(m_lock);
//If 5 tasks are waiting in ProcessEntryAsync method
if(m_count >= 5)
{
//Do some batch processing to obtian values to set for adapterEntry.AdapterEntryId in ProcessEntryAsync
//.......
//.......
m_condition = true;
Monitor.PulseAll(m_lock); // Wakes all waiters AFTER lock is released
}
Monitor.Exit(m_lock);
removedTasks += activeTasks.RemoveAll(t => t.IsCompleted);
Task processingTask = Task.Run(
async () =>
{
await this.ProcessEntryAsync(
entryUpdateInfo,
db)
.ContinueWith(this.ProcessEntryCompleteAsync)
.ConfigureAwait(false);
});
activeTasks.Add(processingTask);
addedTasks++;
}
}
private async Task<bool> ProcessEntryAsync(SyncDatabase db, EntryUpdateInfo entryUpdateInfo)
{
SyncEntryAdapterData adapterEntry =
updateInfo.Entry.AdapterEntries.FirstOrDefault(e => e.AdapterId == this.Config.Id);
if (adapterEntry == null)
{
adapterEntry = new SyncEntryAdapterData()
{
SyncEntry = updateInfo.Entry,
AdapterId = this.Config.Id
};
updateInfo.Entry.AdapterEntries.Add(adapterEntry);
}
m_condition = false;
Monitor.Enter(m_lock);
while (!m_condition)
{
m_count++;
Monitor.Wait(m_lock);
}
m_count--;
adapterEntry.AdapterEntryId = .... //Set Value obtained form batch processing
Monitor.Exit(m_lock);
}
private void ProcessEntryCompleteAsync(Task<bool> task, object context)
{
EntryProcessingContext ctx = (EntryProcessingContext)context;
try
{
string message;
if (task.IsCanceled)
{
Logger.Warning("Processing was cancelled");
message = "The change was cancelled during processing";
}
else if (task.Exception != null)
{
Exception ex = task.Exception;
Logger.Warning("Processing failed with {0}: {1}", ex.GetType().FullName, ex.Message);
message = "An error occurred while synchronzing the changed.";
}
else
{
message = "The change was successfully synchronized";
if (task.Result)
{
//Processing
//...
//...
}
}
}
catch (Exception e)
{
Logger.Info(
"Caught an exception while completing entry processing. " + e);
}
finally
{
}
}
Thanks

Set a WPF Mahapps Progress Dialog

I'm trying to replace my ProgressBar to a Progress Dialog using Mahapps.
So I started writing this:
private void btnClick(object sender, RoutedEventArgs e)
{
ConfRelais();
}
public async void ConfRelais()
{
var controller = await this.ShowProgressAsync("hey", "hoy");
controller.Maximum = 128;
while (flag == 0)
{
string data = RelayBoard_Port.ReadTo("\r\n");
if (data == "ok") { controller.SetMessage("Done Process");
flag = 1; }
else { controller.SetProgress(Int32.Parse(data)); }
}
await controller.CloseAsync();
}
But the progress dialog only displays when it's over.. As I'm still a beginner in c# maybe I'm missing some importants points to setup that kind of function.
You should execute the loop on a background thread:
public async void ConfRelais()
{
var controller = await this.ShowProgressAsync("hey", "hoy");
controller.Maximum = 128;
await Task.Run(() =>
{
while (flag == 0)
{
string data = RelayBoard_Port.ReadTo("\r\n");
if (data == "ok")
{
controller.SetMessage("Done Process");
flag = 1;
}
else { controller.SetProgress(Int32.Parse(data)); }
}
});
await controller.CloseAsync();
}
A single thread cannot both update the UI and execute your loop simultaneously.
You also don't really need a flag. You could just break out of the loop when you receive "ok":
while (true)
{
string data = RelayBoard_Port.ReadTo("\r\n");
if (data == "ok")
{
controller.SetMessage("Done Process");
break;
}
else { controller.SetProgress(Int32.Parse(data)); }
}

Problems working with async Task and Textbox.Text = "Hello"

First of all, sorry because I am so new at C# and I decided to make this question because I have been choked in this for hours.
I have an GUI that works with Google Cloud Speech services and make a Speech-to-Text operation. I share with you the whole method that runs when a button is clicked:
private async Task<object> StreamingMicRecognizeAsync(int seconds)
{
if (NAudio.Wave.WaveIn.DeviceCount < 1)
{
Console.WriteLine("No microphone!");
return -1;
}
GoogleCredential googleCredential;
using (Stream m = new FileStream(#"..\..\credentials.json", FileMode.Open))
googleCredential = GoogleCredential.FromStream(m);
var channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host,
googleCredential.ToChannelCredentials());
var speech = SpeechClient.Create(channel);
var streamingCall = speech.StreamingRecognize();
// Write the initial request with the config.
await streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
StreamingConfig = new StreamingRecognitionConfig()
{
Config = new RecognitionConfig()
{
Encoding =
RecognitionConfig.Types.AudioEncoding.Linear16,
SampleRateHertz = 48000,
LanguageCode = "es-ES",
},
InterimResults = true,
}
});
// Read from the microphone and stream to API.
object writeLock = new object();
bool writeMore = true;
var waveIn = new NAudio.Wave.WaveInEvent();
waveIn.DeviceNumber = 0;
waveIn.WaveFormat = new NAudio.Wave.WaveFormat(48000, 1);
waveIn.DataAvailable +=
(object sender, NAudio.Wave.WaveInEventArgs args) =>
{
lock (writeLock)
{
if (!writeMore) return;
streamingCall.WriteAsync(
new StreamingRecognizeRequest()
{
AudioContent = Google.Protobuf.ByteString
.CopyFrom(args.Buffer, 0, args.BytesRecorded)
}).Wait();
}
};
// Print responses as they arrive.
Task printResponses = Task.Run(async () =>
{
while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Console.WriteLine(alternative.Transcript);
//Textbox1.Text = alternative.Transcript;
}
}
}
});
waveIn.StartRecording();
Console.WriteLine("Speak now.");
Result_Tone.Text = "Speak now:\n\n";
await Task.Delay(TimeSpan.FromSeconds(seconds));
// Stop recording and shut down.
waveIn.StopRecording();
lock (writeLock) writeMore = false;
await streamingCall.WriteCompleteAsync();
await printResponses;
return 0;
}
My problem is that I want to update the content of the Textbox1control but it doesn´t work. It writes perfectly the output into the console with the line Console.WriteLine(alternative.Transcript); but not into my textbox.
If someone could help I would appreciate so much his help.
The problem is that you're using Task.Run, which means your code will be running on a thread-pool thread.
Instead of calling Task.Run(), just move that code into a separate async method:
async Task DisplayResponses(IAsyncEnumerator<StreamingRecognizeResponse> responses)
{
while (await responses.MoveNext(default(CancellationToken)))
{
foreach (var result in responses.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Textbox1.Text = alternative.Transcript;
}
}
}
}
Then call that method directly (without Task.Run) from code that's already on the UI thread (e.g. an event handler).
The async machinery will make sure that after the await expression, you're back on the UI thread (the same synchronization context). So the assignment to the Text property will occur on the UI thread, and all should be well.
For example:
// This would be registered as the event handler for a button
void HandleButtonClick(object sender, EventArgs e)
{
var stream = client.StreamingRecognize();
// Send the initial config request
await stream.WriteAsync(...);
// Presumably you want to send audio data...
StartSendingAudioData(stream);
await DisplayResponses(stream.ResponseStream);
}
Tasks run on seperate threads, so you must Invoke an action that will be performed on the control's thread
Textbox1.Invoke(new Action(() =>
{
Textbox1.Text= "";
}));
Edit: For WPF, I believe the equivalent is
Textbox1.Dispatcher.Invoke(new Action(() =>
{
Textbox1.Text= "";
}));
have you tried using Dispatcher.InvokeASync()?
await Dispatcher.InvokeAsync(() => {while (await streamingCall.ResponseStream.MoveNext(default(CancellationToken)))
{
foreach (var result in streamingCall.ResponseStream
.Current.Results)
{
foreach (var alternative in result.Alternatives)
{
Textbox1.Text = alternative.Transcript;
}
}
}});

Nested Asynchronous function in Silverlight

I am trying to call a nested Asynchronous function but I am not getting the required data.
Since I am using a wcf service with Silverlight I can only use Asynchronous functions.
In my code I am saving a set of rows containing userdata. Before I save it I need to check the username is unique. Now I only need to find out the first one and then break out of loop and show a message to the user.for simplicity sake, I have stripped the function of all the extra data and this is how it looks
private void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.CheckIsUserNameUnique += (s, e) =>
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
_UpdatedUsers = new ObservableCollection<User>();
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
};
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}
In this case I am trying to find if the username is unique,show user a message and return.
Obviously it's not as simple as that.I have tried a couple more different ways but it didn't work. How do I get this working?
I think you can make your life easier by adding a couple of helper functions. The first one is an asynchronous function that checks whether a user is unique. You may need to add some code to set tcs.SetException if there is an error.
private Task<bool> IsUserUniqueAsync(UserViewModel user, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
dataService.CheckIsUserNameUnique += (s, e) =>
{
tcs.SetResult(e.IsUnique);
};
dataService.IsUserNameUnique(user.UserName, user.UserID, Database.CurrentClient.ClientID);
return tcs.Task;
}
The second one updates all the users asynchrnously
public Task<bool> UpdateUsersAsync(ObservableCollection<User> updatedUsers, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
BusyIndicator = true;
BusyMessage = "Saving...";
dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
tcs.SetResult(e.Success);
};
dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, updatedUsers, _DeletedProjectUsers);
return tcs.Task;
}
Then your SaveUsers method becomes a bit simpler.
private async void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
Dictionary<Task<bool>, User> tasks = new Dictionary<Task<bool>, User>();
// start all tasks in parallel
foreach (UserViewModel _User in _AllUsers)
{
if (_User.Dirty && !_User.IsBlank)
{
tasks.Add(IsUserUniqueAsync(_User, _dataService), _User);
}
}
// process each task as it completes
while(tasks.Count() > 0 )
{
var task = await Task.WhenAny(tasks.Keys.ToArray());
if(task.Result)
{
_UpdatedUsers.Add(_User.SaveAsUser());
}
else
{
MessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
tasks.Remove(task);
}
if( await UpdateUsersAsync(_UpdatedUsers, _dataService))
{
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
}
Your code would more or less look like this.
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
int _verifiedUsersCount = 0;
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
//Verify unique users
private void SaveUsers(bool CloseForm)
{
_dataService.CheckIsUserNameUnique += CheckIsUserNameUnique;
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
}
}
//Store verified users to save
private void CheckIsUserNameUnique(object s, CheckIsUserNameUniqueEventArgs e)
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
}
verifiedUsersCount++;
//Call after all the users have been verified for uniqueness
if (_AllUsers.Count() == verifiedUsersCount)
{
OnUniqueUserVerifyComplete();
}
}
//Save verified users
private void OnUniqueUserVerifyComplete()
{
//No unique users
if (_UpdatedUsers.Count < 1) { return; }
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
};
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}

C# task factory timeout

I have to execute a long process operation in a thread and continue by returning the result to a function. Here is my code :
Task<ProductEventArgs>.Factory.StartNew(() =>
{
try
{
// long operation which return new ProductEventArgs with a list of product
}
catch (Exception e)
{
return new ProductEventArgs() { E = e };
}
}).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
The problem is actually I don't have a timeout. I want to put a timer in order to return something like this :
new ProductEventArgs() { E = new Exception("timeout") };
if the timeout is reached.
Can't use await/async.
Thanks a lot !
You should use CancellationTokens:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var token = cts.Token;
Task<ProductEventArgs>.Factory.StartNew(() =>
{
try
{
// occasionally, execute this line:
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException)
{
return new ProductEventArgs() { E = new Exception("timeout") };
}
catch (Exception e)
{
return new ProductEventArgs() { E = e };
}
}).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
This code does what you have expressed here:
var timeout = TimeSpan.FromSeconds(5);
var actualTask = new Task<ProductEventArgs>(() =>
{
var longRunningTask = new Task<ProductEventArgs>(() =>
{
try
{
Thread.Sleep(TimeSpan.FromSeconds(10)); // simulates the long running computation
return new ProductEventArgs();
}
catch (Exception e)
{
return new ProductEventArgs() { E = e };
}
}, TaskCreationOptions.LongRunning);
longRunningTask.Start();
if (longRunningTask.Wait(timeout)) return longRunningTask.Result;
return new ProductEventArgs() { E = new Exception("timed out") };
});
actualTask.Start();
actualTask.Wait();
Console.WriteLine("{0}", actualTask.Result.E); // handling E
As you see longRunningTask is created with TaskCreationOptions.LongRunning option. That way it will have a dedicated Thread for it's execution and does not interfere with normal behavior of ThreadPool by occupying a thread from there for too long - which will be needed for other thing like i.e. UI. That's important for long running tasks.
Note: You could then handle actualTask with ContinueWith but I wanted to express the essence here.
You may use returned task object from StartNew method and then use Wait method to determine timeout.
Task<ProductEventArgs> task = Task<ProductEventArgs>.Factory.StartNew(() => {...});
if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute
{
// throw exception or something else if timeout
}
You can run a Task.Delay(timeout) task in parallel and check what task was first to complete (Task.WhenAny() is very handy in this case):
public void FetchProduct(TimeSpan timeout)
{
var fetchTask = Task<ProductEventArgs>.Factory.StartNew(
() =>
{
try
{
// long operation which return new ProductEventArgs with a list of product
}
catch(Exception e)
{
return new ProductEventArgs() { E = e };
}
});
Task<ProductEventArgs> resultTask;
if(timeout != Timeout.InfiniteTimeSpan)
{
var timeoutTask = Task.Delay(timeout);
resultTask = Task.WhenAny(resultTask, timeoutTask).ContinueWith<ProductEventArgs>(
t =>
{
// completed task is the result of WhenAny
if(t.Result == fetchTask)
{
return fetchTask.Result;
}
else
{
return new ProductEventArgs() { E = new TimeoutException() };
}
});
}
else
{
resultTask = fetchTask;
}
resultTask.ContinueWith(x => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
}
Note that this solution doesn't have any cancellation logic, and your long running task will be still running even if it times out.
Just start another task within the main task (surrogate):
Task.Factory.StartNew(() =>
{
// returns a string result
var tsk = new Task<string>(() => { return VeryImportantThingsToDo(); });
try
{
tsk.Start();
if (!tsk.Wait(5000))
throw new TimeoutException();
return tsk.Result;
}
catch (TimeoutException)
{
// Jabba Dabba Doooooooohhhhhh
}
return "<unknown>";
}).ContinueWith((o) => string result = o.Result));

Categories