Delay main thread while another thread is running - c#

I would like to import a CSV file in its own thread. While the file is imported and processed I would like to delay/stop the main thread until the processing have ended. See the code below:
// Read from CSV file in a seperate thread
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
reader = new CSVReader(myFile);
reader.DataReader();
// Get temperature and time data from CSV file
// and copy the data into each List<String>
Temperature = new List<string>(reader.GetTemperature());
Time = new List<string>(reader.GetTime());
}).Start();
// Bind data to GridView
dtgCsvData.ItemsSource = Time.Zip(Temperature, (t, c) => new { Time = t, Temperature = c });
When the application is running a error occur, since the two Lists are null.
How do I achieve this?

This was created using linqpad... You can either use a task or async keyword as follows.
void Main()
{
Task<TimeAndTemp> timeAndTempTask = GetTimeAndTemp();
timeAndTempTask.ContinueWith (_ =>
{
timeAndTempTask.Result.Time.Dump();
timeAndTempTask.Result.Temperature.Dump();
});
}
Task<TimeAndTemp> GetTimeAndTemp()
{
var tcs = new TaskCompletionSource<TimeAndTemp>();
new Timer (_ => tcs.SetResult (new TimeAndTemp())).Change (3000, -1);
return tcs.Task;
}
public class TimeAndTemp
{
public DateTime Time = DateTime.Now;
public int Temperature = 32;
}
async version using async await keywords.
async void Main()
{
TimeAndTemp tt = await GetTimeAndTemp();
tt.Time.Dump();
tt.Temperature.Dump();
}
async Task<TimeAndTemp> GetTimeAndTemp()
{
return new TimeAndTemp();
}
public class TimeAndTemp
{
public DateTime Time = DateTime.Now;
public int Temperature = 32;
}

You probably don't really want to stop the main thread. If this is a GUI application, you still want the main UI thread to respond to Windows messages and the like. What you want is to run that piece of code after the data has been read. Why not have it be called by the worked thread after it reads the data?

Related

How to create a task that watches the size of a file in a c# console application

I'm working on a C# project that will need to create text files and fill them with guids using an array of 25 tasks. I want to use another task separate from the writing tasks to monitor the size of the file at 0.5 second intervals.
I'm struggling to figure out a way to do this. I know with a C# WPF application I could use the FILEIO class but I don't think I have access to that using a console app.
What could I use instead of the FILEIO class to create this task and how would I create it?
you can create a new Thread and use the Length property of a System.IO.FileInfo object to get the size of a file.
See this link for more details on Threading.
How about something like this. Everything is asynchronous. The only thread created monitors the count (so that you can see what's going on - which is the point of this, I think).
First I create a class like this:
internal class GuidWriter
{
public string Folder { get; }
public string FileNamePattern { get; }
public int CountOfFiles { get; }
public int CountOfGuids { get; }
public int TotalGuidsToWrite { get; }
private int _currentGuidCount = 0;
public int CurrentGuidCount { get { return _currentGuidCount; } }
public GuidWriter(string folder, string fileNamePattern, int countOfFiles, int countOfGuids)
{
Folder = folder;
FileNamePattern = fileNamePattern;
CountOfFiles = countOfFiles;
CountOfGuids = countOfGuids;
TotalGuidsToWrite = countOfFiles * countOfGuids;
}
public async Task WriteAllFiles()
{
var writeTaskList = new List<Task>(CountOfFiles);
for (int i = 0; i < CountOfFiles; i++)
{
var writeTask = WriteGuidsToOneFile(i + 1);
writeTaskList.Add(writeTask);
}
await Task.WhenAll(writeTaskList);
}
private async Task WriteGuidsToOneFile(int fileNumber)
{
var fileName = string.Format(FileNamePattern, fileNumber);
var filePathName = Path.Combine(Folder, fileName);
using (StreamWriter writer = File.CreateText(filePathName))
{
for (var i = 0; i < CountOfGuids; ++i)
{
var guidString = Guid.NewGuid().ToString();
await writer.WriteLineAsync(guidString);
Interlocked.Increment(ref _currentGuidCount);
}
}
}
}
You create one of these things, tell it how it should work (in the constructor) and then let it rip in the WriteAllFiles (which is async, and which you should await).
It uses Interlocked.Increment on the Guid count - if the framework doesn't anything in threads, I want to make sure that I don't mess up the count.
Then in the main program, I create a Monitor function that counts the number of Guids created and outputs them to the console. It runs in a separate thread, and will go away when it's CancellationToken is canceled:
public static async Task MonitorGuidProduction (GuidWriter guidWriter, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
var monitorString = $"{guidWriter.CurrentGuidCount}/{guidWriter.TotalGuidsToWrite}";
Console.WriteLine(monitorString);
await Task.Delay(500);
}
}
Then, in the main program, I put it all together:
static async Task Main(string[] args)
{
using (var cancelTokenSource = new CancellationTokenSource())
{
var cancelToken = cancelTokenSource.Token;
var folder = #"C:\temp\guids";
var pattern = "GuidFile{0}.txt";
var guidWriter = new GuidWriter(folder, pattern, CountOfFiles, CountOfGuids);
var monitorTask = Task.Run(() => MonitorGuidProduction(guidWriter, cancelToken));
cancelToken));
await guidWriter.WriteAllFiles();
cancelTokenSource.Cancel();
await monitorTask;
Console.WriteLine($"{guidWriter.CurrentGuidCount} Guids written to {CountOfFiles} files");
Console.ReadLine();
}
}
I create an instance of a GuidWriter and, just before I let it go (by calling guidWriter.WriteAllFiles, I start up my monitor function in another thread. I do that by running Task.Run, but not awaiting its result until everything else is done (getting the cleanup just right).
Then I await the call to guidWriter.WriteAllFiles, and when it completes, I signal my cancellation token to stop the monitor task/thread.

Is there any solution to run my function infinite time in background without hanging UI?

I had tried background worker, thread and task but the procedure are so long to get a solution according to my question. suppose I use a task, I can't add any textboxes in ABC function which is called in button_click. When I use textbox inside button click function on the place of ABC function it's worked. But this process is not fulfil my requirement.
If I called this function directly into buttonclick event it's hang my UI.
Here is the example code of ABC function.
public void ABC()
{
While(true)
{
richTextBox1.AppendText("Hello");
richTextBox2.AppendText("Tesing");
}
}
If anyone have an idea to achieve this, please tell me.
I am trying this because my sensor gives me data on continuous basis and I used these values to draw a graph, so I tried to run that in background to update my graphs on continuous basis.
Wait let me explain I have sensor which sends there data on API every 5 minutes in JSON format. Now my code fetching data from API and display a graph after button click. When I click on button my graph is updated with new data but I want to try to convert this manual process into automatic process. I mean when I click on button my function should have run continuously and update data on graph without hanging UI because I have to perform another operations on graph. Here is my function with original code:
public void EnvlopGraph()
{
//while (true)
//{
graph = new Graph();
//frmdeviceconfig deviceinfo = new frmdeviceconfig(this);
grpboxselectaxis.Enabled = false;
chkboxxaxis.Checked = true;
chkboxyaxis.Checked = false;
chkboxzaxis.Checked = false;
frm.GetSensorId();
frm.GetOverall();
chartview1.Visible = true;
grpboxselectaxis.Visible = true;
double[] XAxisRange;
envlpxfft.Clear();
envlpyfft.Clear();
envlpxtime.Clear();
envlpytime.Clear();
var client = new RestClient(frm.ClientURL);
var request = new RestRequest($"api/traces", Method.GET);
try
{
IRestResponse response = client.Execute(request);
JsonDeserializer deserial = new JsonDeserializer();
dynamic obj = deserial.Deserialize<dynamic>(response);
var objindexcount = obj.Count;
var TracesData = obj[objindexcount - 1]; //this is applicable on current Bearing data only
//var TracesData = obj[objindexcount - 2]; // for current Tri_Acc Data (x,y,z)
var SerialNumber = TracesData["serialNumber"];
if (SerialNumber == frmdeviceconfig.stpointsensor)
{
var RouteTime = TracesData["routeTime"];
var SampleTime = TracesData["sampleTime"];
var Name = TracesData["name"];
var SignalPath = TracesData["signalPath"];
var Range = TracesData["range"];
string SampleRate = TracesData["sampleRate"];
string[] SR = SampleRate.Split('S', 'a', 'm', 'p', 'l', 'e', 'R', 'a', 't', 'e', '_');
double SampleRateVal = Convert.ToDouble(SR[11]);
string TraceLength = TracesData["traceLength"];
var XAxisTrace = TracesData["xAxisTrace"];
string[] TL = TraceLength.Split('T', 'r', 'a', 'c', 'e', 'L', 'e', 'n', 'g', 't', 'h', '_');
double TraceLengthVal = Convert.ToDouble(TL[12]);
double xtimerange = Convert.ToDouble((TraceLengthVal / TraceLengthVal) / TraceLengthVal);
if (chartview1.Controls.Count > 0)
{
chartview1.Controls.Clear();
chartview1.Controls.Remove(graph);
}
if (XAxisTrace != null)
{
var XAdcRangePercent = XAxisTrace["adcRangePercent"];
var XClipped = XAxisTrace["clipped"];
var XRangeApplied = XAxisTrace["rangeApplied"];
var XGravityRemoved = XAxisTrace["gravityRemoved"];
var XTimeWave = XAxisTrace["timewave"];
var xaxisdatalength = XTimeWave.Count;
XData = new double[xaxisdatalength];
XAxisRange = new double[xaxisdatalength];
for (int i = 0; i < xaxisdatalength; i++)
{
XData[i] = XTimeWave[i];
XAxisRange[i] = i * xtimerange;
}
//Add graph
envlpxtime.Add(XAxisRange);
envlpytime.Add(XData);
if (Display == 1)
{
if (GraphType != "FFT")
{
graph.DrawLineGraph(envlpxtime, envlpytime);
}
else
{
//fft graph for x axis
FFTConversion fft = new FFTConversion();
if (XData == null)
{
MessageBox.Show("TimeData is not available");
}
else
{
double[] fftdata = fft.ConvertTimeDataToFFT(XData);
chartview1.Visible = true;
string[] linekhz = Name.Split('B', '_', 'X', 'R', 'G', 'L', 'H');
double lines = Convert.ToDouble(linekhz[8]);
double hz = Convert.ToDouble(linekhz[10]);
double fftXrange = hz / lines;
for (int k = 0; k < fftdata.Length; k++)
{
XAxisRange[k] = k * fftXrange;
}
envlpxfft.Add(XAxisRange);
envlpyfft.Add(fftdata);
graph.DrawLineGraph(envlpxfft, envlpyfft);
}
}
graph.Dock = DockStyle.Fill;
chartview1.Controls.Add(graph);
}
}
else
{
}
}
}
catch (Exception ex)
{
}
}
I believe that there is a better way, but sometimes you can't just change what is already there… In those cases, I use the Producer/Consumer Pattern for problems that are similar to yours.
1) Create the ProducerConsumer class.
public class ProducerConsumer<T>
{
private readonly BlockingCollection<T> mCollection = new BlockingCollection<T>(100);
private readonly Action<T> mConsumer;
private readonly object SYNC_LOCK = new object();
public ProducerConsumer(Action<T> consumer) {
mConsumer = consumer;
}
public void Produce(T obj) {
mCollection.Add(obj);
}
// If using multiple producers
public void ThreadSafeProduce(T obj) {
lock (SYNC_LOCK ) {
Produce(obj);
}
}
private void Loop() {
while (true) {
var obj = mCollection.Take();
if (obj == null) return;
mConsumer(obj);
}
}
public void Start() {
Task.Run(() => Loop());
}
}
2) Example of how to use it
public partial class Form1 : Form
{
private ProducerConsumer<string> mProducerConsumer;
public Form1()
{
InitializeComponent();
mProducerConsumer = new ProducerConsumer<string>(Consumer);
mProducerConsumer.Start();
FakeSensorReadings();
}
private void FakeSensorReadings()
{
Task.Run(() =>
{
while (true)
{
mProducerConsumer.Produce("Teste string\r\n");
Thread.Sleep(100);
}
});
}
private void Consumer(string str) {
// Run on Main Thread
this.Invoke(new MethodInvoker(() =>
{
textBox1.Text += str;
}));
}
}
HINT
You can use any object type that you want, like int, float, struct, custom objects, etc.
So you have a Sensor class that produces data, and you have another class that processes (= consumes) the produced data. Sometimes the Producer produces more data than the Consumer can process, other times the Consumer has enough time to process the produced data.
A problem like this screams for the Producer-Consumer pattern: a Producer produces data that a Consumer processes in a different tempo: sometimes the Producer is faster, sometimes the Consumer is faster.
For this, Microsoft came up with the Dataflow Task Parallel Library (TPL). You can download the code using the nuget package manager.
Let's assume your Sensor produces a stream of SensorData, sometimes faster, sometimes slower.
Your Consumer process needs to take this Sensor data and process it. While this data is being processed, the Sensor might produce new SensorData. This SensorData needs to be buffered.
This buffering is done using the TPL BufferBlock. Whenever your Sensor produces some SensorData it Adds the data to the BufferBlock, and starts Producing the next SensorData.
Meanwhile, the Consumer does nothing but wait until there is some SensorData in the BufferBlock. As soon as it arrives, it removes it from the BufferBlock and processes the SensorData. When finished processing, it waits until there is SensorData again.
So if the Producer is (temporarily) faster than the Consumer, then there will be several SensorData in the BufferBlock. If the Consumer is faster, the BufferBlock will regularly be empty.
This process stops when the Sensor knows that there is no more data. It notifies the BufferBlock. When all SensorData in the BufferBlock are processed, the Consumer is notified that no more data is to be expected.
class SensorData {...};
class Sensor
{
// send Produced SensorData to this ITargetBlock:
public ITargetBlock<SensorData> DataBuffer {get; set;}
private SensorData ReadSensor() {...}
public async Task ProduceDataAsync(CancellationToken token)
{
// TODO: check if this.TargetBuffer and token not null
while (!token.IsCancellationRequested)
{
SensorData sensorData = this.ReadSensor();
await this.TargetBuffer.SendAsync(token);
}
// if here: cancellation requested. Stop producing SensorData
// notify that no data will be produced anymore
this.TargetBuffer.Complete();
}
}
The Consumer:
class Consumer
{
// the Consumer will listen for data here:
public ISourceBlock<SensorData> DataBuffer {get; set;}
private void ProcessSensorData(SensorData sensorData) {...}
public async Task ConsumeDataAsync()
{
// TODO: check if DataBuffer
// as long as there is SensorData expected: wait for it and process
while (await this.DataBuffer.OutputAvailableAsync())
{
// There is some data; fetch it and process it
SensorData sensorData = await this.DataBuffer.ReceiveAsync();
this.ProcessSensorData(sensorData);
}
// if here: no more SensorData expected
}
}
Putting it all together
BufferBlock<SensorData> buffer = new BufferBlock<SensorData>();
Sensor sensor = new Sensor
{
DataBuffer = buffer,
}
Consumer consumer = new Consumer
{
DataBuffer = buffer,
}
Now everything is ready to be started. For instance when pressing a button:
async void OnButtonStart_Clicked(object sender, ...)
{
this.buttonStart.Enabled = false; // to prevent starting again
this.buttonStop.Enabled = true; // so we can stop the process
await this.StartProcessingAsync();
this.buttonStop.Enabled = false;
this.buttonStart.Enabled = true;
}
private CancellationTokenSource CancellationTokenSource {get; set;}
async Task StartProcessingAsync()
{
using (this.CancellationTokenSource = new CancellationTokenSource())
{
CancellationToken token = this.CancellationTokenSource.Token;
// start Producing and Consuming:
Task producerTask = sensor.ProduceDataAsync(token);
Task consumerTask = consumer.ConsumeDataAsync();
// continue producing and consuming until both tasks are finished
await Taks.WhenAll(new Task[] {producerTask, consumerTask});
}
}
To stop the process:
async void StopButton_ClickedAsync(object sender, ...)
{
this.NotifyProducerBeingCancelled(); // notify the operator
// Start the cancellation process
this.CancellationTokenSource.Cancel();
}
Cancelling the CancellationTokenSource will notify all Tokens from this Source. The Producer has such a token. It will check regularly whether cancellation is requested. If so, it will stop producing SensorData and notify the Buffer that no data is to be expected anymore. The method will return.
Meanwhile the Consumer is happily consuming SensorData. If all Produced SensorData has been processed, it sees that no more data is to be expected. The method will return.
Method StartProcessingAsync was waiting until both tasks ProduceDataAsync and ConsumeDataAsync are finished. When both are finished it will Enable and Disable the buttons again and return.
If the operator clicks the Stop Button several times before the Producer and Consumer are stopped, then only the CancellationTokenSource is cancelled again, which won't do anything.
Note that this whole thing is done by one thread. Or to be more accurate: only one context is used, this means that it is as if only one thread does everything. Therefore there is no need for you to protect using mutexes or semaphores. No need for InvokeRequired in method ProcessSensorData, because the thread has the UI context, and thus can update UI elements.
If the update of the UI elements was only as an example in your question, and you don't need to update UI elements at all, but for instance only save data in a file, consider to add ConfigureAwait(false) in your await statements
The Producer is

Set property value when all threads are finished?

In my application there are three threads like:
private Thread _analysisThread;
private Thread _head2HeadThread;
private Thread _formThread;
and each thread is started in the following way:
if (_analysisThread == null || !_analysisThread.IsAlive)
{
_analysisThread = new Thread(() => { Analysis.Logic(match); });
_analysisThread.Start();
}
I've a ListView where the user can select an item and then start again the thread, but I want prevent this 'cause the methods inside each thread are heavy, so need time to complete them.
Until now I want disable the ListView selection, so I did:
<ListView IsEnabled="{Binding IsMatchListEnabled}">
private bool _isMatchListEnabled = true;
public bool IsMatchListEnabled
{
get { return _isMatchListEnabled; }
set
{
_isMatchListEnabled = value;
OnPropertyChanged();
}
}
before a new Thread start I do: IsMatchListEnabled = false; but what I need to do is check if all thread are finished and then do: IsMatchListEnabled = true;, actually if I enable the ListView after all thread, I get the ListView even enabled 'cause the Thread code is async, and the code outside the Thread is sync, so actually this property is useless.
What I tried to avoid this is create an infinite loop like this:
while (true)
{
if (!_analysisThread.IsAlive && !_head2HeadThread.IsAlive && !_formThread.IsAlive)
{
IsMatchListEnabled = true;
break;
}
}
this loop is placed after all threads execution, but as you can imagine, this will freeze the application.
Any solution?
All comments are correct — it's better to use Tasks. Just to answer OP's question.
You can synchronize threads with ManualResetEvent, having an array of events by the number of threads and one additional thread to change IsMatchListEnabled when all threads are finished.
public static void SomeThreadAction(object id)
{
var ev = new ManualResetEvent(false);
events[id] = ev; // store the event somewhere
Thread.Sleep(2000 * (int)id); // do your work
ev.Set(); // set the event signaled
}
Then, somewhere else we need to initialize waiting routine.
// we need tokens to be able to cancel waiting
var cts = new CancellationTokenSource();
var ct = cts.Token;
Task.Factory.StartNew(() =>
{
bool completed = false;
while (!ct.IsCancellationRequested && !completed)
{
// will check if our routine is cancelled each second
completed =
WaitHandle.WaitAll(
events.Values.Cast<ManualResetEvent>().ToArray(),
TimeSpan.FromSeconds(1));
}
if (completed) // if not completed, then somebody cancelled our routine
; // change your variable here
});
Complete example can be found and viewed here.
I would suggest using Microsoft's Reactive Framework for this. It's more powerful than tasks and the code is far simpler than using threads.
Let's say you have 3 long-running operations:
Action huey = () => { Console.WriteLine("Huey Start"); Thread.Sleep(5000); Console.WriteLine("Huey Done"); };
Action dewey = () => { Console.WriteLine("Dewey Start"); Thread.Sleep(5000); Console.WriteLine("Dewey Done"); };
Action louie = () => { Console.WriteLine("Louie Start"); Thread.Sleep(5000); Console.WriteLine("Louie Done"); };
Now you can write the following simple query:
IObservable<Unit> query =
from a in new [] { huey, dewey, louie }.ToObservable()
from u in Observable.Start(() => a())
select u;
You run it like this:
Stopwatch sw = Stopwatch.StartNew();
IDisposable subscription = query.Subscribe(u => { }, () =>
{
Console.WriteLine("All Done in {0} seconds.", sw.Elapsed.TotalSeconds);
});
The results I get are:
Huey Start
Dewey Start
Louie Start
Huey Done
Louie Done
Dewey Done
All Done in 5.0259197 seconds.
Three 5 second operations complete in 5.03 seconds. All in parallel.
If you want to stop the computation early just call subscription.Dispose().
NuGet "System.Reactive" to get the bits.

ASP.NET - async programming

I am trying to understand async programming, and I had a question. It is regarding the following functions below.
public async void TestAsyncCall() {
Task<string> TaskResult1 = DoSomethingAsync();
string Result2 = DoSomething();
string Result1 = await TaskResult1;
}
public string DoSomething() {
return "synch";
}
public async Task<string> DoSomethingAsync() {
await Task.Delay(10000);
return "asynch";
}
In the function call TestAsyncCall(), would one thread be used to execute DoSomethingAsync(), and another thread to execute DoSomething()?
Then when await is encountered, it would wait for DoSomethingAsync() to complete and release that thread (while also not blocking the original thread)?
Or will this not warrant any new threads being created? In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
I recommend you read my article on async ASP.NET.
Or will this not warrant any new threads being created?
This won't create any new threads. In particular, async and await by themselves won't create any new threads.
On ASP.NET, it's likely that the code after an await will run on a different thread than the code before that await. This is just exchanging one thread for another, though; no new threads are created.
In that case will the DoSomethingAsync call be relevant only if it were to deal with some external resource?
The primary use case for async is to deal with I/O, yes. This is particularly true on ASP.NET.
As #Stepehen-cleary said, "In particular, async and await by themselves won't create any new threads."
This next example is taken from the book: "C sharp in Depth" by John Skeet, chapter 15 pp.465:
class AsyncForm : Form
{
/* The first part of listing 15.1 simply creates the UI and hooks up an event handler for
the button in a straightforward way */
Label label;
Button button;
public AsyncForm()
{
label = new Label {
Location = new Point(10, 20),
Text = "Length"
};
button = new Button {
Location = new Point(10, 50),
Text = "Click"
};
button.Click += DisplayWebSiteLength;
AutoSize = true;
Controls.Add(label);
Controls.Add(button);
}
/* When you click on the button, the text of the book’s home page is fetched
and the label is updated to display the HTML lenght in characters */
async void DisplayWebSiteLength(object sender, EventArgs e)
{
label.Text = "Fetching...";
using (HttpClient client = new HttpClient())
{
string text =
await client.GetStringAsync("http://csharpindepth.com");
label.Text = text.Length.ToString();
}
}
/* The label is updated to display the HTML length in characters D. The
HttpClient is also disposed appropriately, whether the operation succeeds or fails—
something that would be all too easy to forget if you were writing similar asynchronous
code in C# 4 */
}
With this in mind, let's take a look to your code, you have Result1 and Result2, there's no point in having one asynchronous task waiting for a synchronous task to be finished. I would use Parallelism so you can perform both methods but to return something like two sets of Data, performing LINQ queries at the same time.
Take a look to this short example about Parallelism with Async Tasks:
public class StudentDocs
{
//some code over here
string sResult = ProcessDocs().Result;
//If string sResult is not empty there was an error
if (!sResult.Equals(string.Empty))
throw new Exception(sResult);
//some code over there
##region Methods
public async Task<string> ProcessDocs()
{
string sResult = string.Empty;
try
{
var taskStuDocs = GetStudentDocumentsAsync(item.NroCliente);
var taskStuClasses = GetStudentSemesterClassesAsync(item.NroCliente, vencimientoParaProductos);
//We Wait for BOTH TASKS to be accomplished...
await Task.WhenAll(taskStuDocs, taskStuClasses);
//Get the IList<Class>
var docsStudent = taskStuDocs.Result;
var docsCourses = taskStuClasses.Result;
/*
You can do something with this data ... here
*/
}
catch (Exception ex)
{
sResult = ex.Message;
Loggerdb.LogInfo("ERROR:" + ex.Message);
}
}
public async Task<IList<classA>> GetStudentDocumentsAsync(long studentId)
{
return await Task.Run(() => GetStudentDocuments(studentId)).ConfigureAwait(false);
}
public async Task<IList<classB>> GetStudentSemesterCoursessAsync(long studentId)
{
return await Task.Run(() => GetStudentSemesterCourses(studentId)).ConfigureAwait(false);
}
//Performs task to bring Student Documents
public IList<ClassA> GetStudentDocuments(long studentId)
{
IList<ClassA> studentDocs = new List<ClassA>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentGrades(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentDocs.Add(new ClassA(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
Convert.ToInt64(item.studentAge),
item.studentProfile,
item.studentRecord
));
}
}
return studentDocs;
}
//Performs task to bring Student Courses per Semester
public IList<ClassB> GetStudentSemesterCourses(long studentId)
{
IList<ClassB> studentCourses = new List<ClassB>();
//Let's execute a Stored Procedured map on Entity Framework
using (ctxUniversityData oQuery = new ctxUniversityData())
{
//Since both TASKS are running at the same time we use AsParallel for performing parallels LINQ queries
foreach (var item in oQuery.GetStudentCourses(Convert.ToDecimal(studentId)).AsParallel())
{
//These are every element of IList
studentCourses.Add(new ClassB(
(int)(item.studentId ?? 0),
item.studentName,
item.studentLastName,
item.carreerName,
item.semesterNumber,
Convert.ToInt64(item.Year),
item.course ,
item.professorName
));
}
}
return studentCourses;
}
#endregion
}

Is there an await statement for threads?

Hi I would like to know if there is something similiar to the await statement, which is used with tasks, which I can implement with threads in c#?
What I want to do is:
Start Thread A, compute some data and put the result on variable x.
After that variable x is transferred to another thread B and at the same time
Thread A starts again to compute some data, while thread B starts another calculation with the result x.
UPDATE: Ok there seems to be some confusion so I will be more accurate in my description:
I use two sensors which produce data. The data needs to be retrieved in such a way that SensorA data is retrieved (which takes a long time) and immediately after that the data from SensorB must be retrieved in another Thread, while SensorA continues retrieving another data block. The problem is i cant queue the data of both sensors in the same queue, but I need to store the data of both sensor in ONE data structure/object.
My idea was like that:
Get Data from Sensor A in Thread A.
Give result to Thread B and restart Thread A.
While Thread A runs again Thread B gets Data from Sensor B and computes the data from Sensor A and B
You can assume that Thread A always needs a longer time than Thread B
As I said in a comment. This looks like classic Producer/Consumer, for which we can use e.g. a BlockingCollection.
This is a slight modification of the sample from that page:
BlockingCollection<Data> dataItems = new BlockingCollection<Data>(100);
// "Thread B"
Task.Run(() =>
{
while (!dataItems.IsCompleted)
{
Data dataA = null;
try
{
dataA = dataItems.Take();
}
catch (InvalidOperationException) { }
if (dataA != null)
{
var dataB = ReadSensorB();
Process(dataA,dataB);
}
}
Console.WriteLine("\r\nNo more items to take.");
});
// "Thread A"
Task.Run(() =>
{
while (moreItemsToAdd)
{
Data dataA = ReadSensorA();
dataItems.Add(dataA);
}
// Let consumer know we are done.
dataItems.CompleteAdding();
});
And then moreItemsToAdd is just whatever code you need to have to cope with needing to shut this process down.
I'm not sure why you're avoiding the use of tasks? Maybe you're on an older version of .net? If so, BlockingCollection as Damien suggested is also not an option. If you're using "normal" threads, you can use a waithandle to signal results between threads. For example, an AutoResetEvent.
private int a;
private AutoResetEvent newResult = new AutoResetEvent(false);
private void ThreadA()
{
while (true)
{
a = GetSensorA();
newResult.Set();
}
}
private void ThreadB()
{
int b;
while (true)
{
newResult.WaitOne();
b = GetSensorB(); // or before "waitone"
Console.WriteLine(a + b); // do something
}
}
edit: had slight mistake in there with the reset, thanks for pointing out Damien - updated
If you can use .Net 4.5 or later, then the best way to approach this is to use the DataFlow component of the TPL.
(You must use NuGet to install DataFlow; it's not part of the CLR by default.)
Here's a sample compilable console application which demonstrates how to use DataFlow to do it:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
namespace SensorDemo
{
public sealed class SensorAData
{
public int Data;
}
public sealed class SensorBData
{
public double Data;
}
public sealed class SensorData
{
public SensorAData SensorAData;
public SensorBData SensorBData;
public override string ToString()
{
return $"SensorAData = {SensorAData.Data}, SensorBData = {SensorBData.Data}";
}
}
class Program
{
static void Main()
{
var sensorADataSource = new TransformBlock<SensorAData, SensorData>(
sensorAData => addSensorBData(sensorAData),
dataflowOptions());
var combinedSensorProcessor = new ActionBlock<SensorData>(
data => process(data),
dataflowOptions());
sensorADataSource.LinkTo(combinedSensorProcessor, new DataflowLinkOptions { PropagateCompletion = true });
// Create a cancellation source that will cancel after a few seconds.
var cancellationSource = new CancellationTokenSource(delay:TimeSpan.FromSeconds(20));
Task.Run(() => continuouslyReadFromSensorA(sensorADataSource, cancellationSource.Token));
Console.WriteLine("Started reading from SensorA");
sensorADataSource.Completion.Wait(); // Wait for reading from SensorA to complete.
Console.WriteLine("Completed reading from SensorA.");
combinedSensorProcessor.Completion.Wait();
Console.WriteLine("Completed processing of combined sensor data.");
}
static async Task continuouslyReadFromSensorA(TransformBlock<SensorAData, SensorData> queue, CancellationToken cancellation)
{
while (!cancellation.IsCancellationRequested)
await queue.SendAsync(readSensorAData());
queue.Complete();
}
static SensorData addSensorBData(SensorAData sensorAData)
{
return new SensorData
{
SensorAData = sensorAData,
SensorBData = readSensorBData()
};
}
static SensorAData readSensorAData()
{
Console.WriteLine("Reading from Sensor A");
Thread.Sleep(1000); // Simulate reading sensor A data taking some time.
int value = Interlocked.Increment(ref sensorValue);
Console.WriteLine("Read Sensor A value = " + value);
return new SensorAData {Data = value};
}
static SensorBData readSensorBData()
{
Console.WriteLine("Reading from Sensor B");
Thread.Sleep(100); // Simulate reading sensor B data being much quicker.
int value = Interlocked.Increment(ref sensorValue);
Console.WriteLine("Read Sensor B value = " + value);
return new SensorBData {Data = value};
}
static void process(SensorData value)
{
Console.WriteLine("Processing sensor data: " + value);
Thread.Sleep(1000); // Simulate slow processing of combined sensor values.
}
static ExecutionDataflowBlockOptions dataflowOptions()
{
return new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = 1,
BoundedCapacity = 1
};
}
static int sensorValue;
}
}

Categories

Resources