c# do the equivalent of restarting a Task with some parameter - c#

The main idea here is to fetch some data from somewhere, when it's fetched start writing it, and then prepare the next batch of data to be written, while waiting for the previous write to be complete.
I know that a Task cannot be restarted or reused (nor should it be), although I am trying to find a way to do something like this :
//The "WriteTargetData" method should take the "data" variable
//created in the loop below as a parameter
//WriteData basically do a shedload of mongodb upserts in a separate thread,
//it takes approx. 20-30 secs to run
var task = new Task(() => WriteData(somedata));
//GetData also takes some time.
foreach (var data in queries.Select(GetData))
{
if (task.Status != TaskStatus.Running)
{
//start task with "data" as a parameter
//continue the loop to prepare the next batch of data to be written
}
else
{
//wait for task to be completed
//"restart" task
//continue the loop to prepare the next batch of data to be written
}
}
Any suggestion appreciated ! Thanks. I don't necessarily want to use Task, I just think it might be the way to go.

This may be over simplifying your requirements, but would simply "waiting" for the previous task to complete work for you? You can use Task.WaitAny and Task.WaitAll to wait for previous operations to complete.
pseudo code:
// Method that makes calls to fetch and write data.
public async Task DoStuff()
{
Task currTask = null;
object somedata = await FetchData();
while (somedata != null)
{
// Wait for previous task.
if (currTask != null)
Task.WaitAny(currTask);
currTask = WriteData(somedata);
somedata = await FetchData();
}
}
// Whatever method fetches data.
public Task<object> FetchData()
{
var data = new object();
return Task.FromResult(data);
}
// Whatever method writes data.
public Task WriteData(object somedata)
{
return Task.Factory.StartNew(() => { /* write data */});
}

The Task class is not designed to be restarted. so you Need to create a new task and run the body with the same Parameters. Next i do not see where you start the task with the WriteData function in its body. That will property Eliminate the call of if (task.Status != TaskStatus.Running) There are AFAIK only the class Task and Thread where task is only the abstraction of an action that will be scheduled with the TaskScheduler and executed in different threads ( when we talking about the Common task Scheduler, the one you get when you call TaskFactory.Scheduler ) and the Number of the Threads are equal to the number of Processor Cores.
To you Business App. Why do you wait for the execution of WriteData? Would it be not a lot more easy to gater all data and than submit them into one big Write?

something like ?
public void Do()
{
var task = StartTask(500);
var array = new[] {1000, 2000, 3000};
foreach (var data in array)
{
if (task.IsCompleted)
{
task = StartTask(data);
}
else
{
task.Wait();
task = StartTask(data);
}
}
}
private Task StartTask(int data)
{
var task = new Task(DoSmth, data);
task.Start();
return task;
}
private void DoSmth(object time)
{
Thread.Sleep((int) time);
}

You can use a thread and an AutoResetEvent. I have code like this for several different threads in my program:
These are variable declarations that belong to the main program.
public AutoResetEvent StartTask = new AutoResetEvent(false);
public bool IsStopping = false;
public Thread RepeatingTaskThread;
Somewhere in your initialization code:
RepeatingTaskThread = new Thread( new ThreadStart( RepeatingTaskProcessor ) ) { IsBackground = true; };
RepeatingTaskThread.Start();
Then the method that runs the repeating task would look something like this:
private void RepeatingTaskProcessor() {
// Keep looping until the program is going down.
while (!IsStopping) {
// Wait to receive notification that there's something to process.
StartTask.WaitOne();
// Exit if the program is stopping now.
if (IsStopping) return;
// Execute your task
PerformTask();
}
}
If there are several different tasks you want to run, you can add a variable that would indicate which one to process and modify the logic in PerformTask to pick which one to run.
I know that it doesn't use the Task class, but there's more than one way to skin a cat & this will work.

Related

Replace 'BackgroundWorker' With 'Thread '

I want to replace BackgroundWorker in my winform application with a Thread.
The goal is do the the jobs in a new thread other than UI-thread & prevent program hang during run.
So i did this :
private void radBtn_start_Click(object sender, EventArgs e)
{
try
{
string thread_name = "trd_" + rnd.Next(99000, 10000000).ToString();
Thread thread = new Thread(new ThreadStart(Thread_Method));
thread.Name = thread_name;
thread.Start();
}
catch (System.Exception ex)
{
MessageBox.Show("Error in radBtn_start_Click() Is : " + ex.ToString());
}
}
public void Thread_Method()
{
...Some Jobs
Thread.Sleep(20000);
...Some Jobs After Delay
Thread.Sleep(20000);
...Some Jobs After Delay
this.Invoke(new MethodInvoker(delegate
{
radTextBoxControl1.Text += DateTime.Now.ToString() + " : We are at end of search( " + radDropDownList1.SelectedItem.Tag + " ) = -1" + Environment.NewLine;
}));
}
But after running these codes UI hangs during sleep.
What is the correct codes for my purpose?
You don't have to create a new Thread, your process already has a pool of threads anxiously waiting to do something for you
Usually the threads in the thread pool are used when you use async-await. However, you can also use them for heavy calculations
My advice is to make your thread_method async. This has the advantage, that whenever your thread_method has to wait idly for another process to finish, like writing data to a file, fetching items from a database, or reading information from the internet, the thread is available for the thread pool to do other tasks.
If you are not familiar with async-await: this interview with Eric Lippert really helped me to understand what happens when you use async-await. Search somewhere in the middle for async-await.
One of the nice things about async-await, is that the executing thread has the same "context" as the UI-thread, so this thread can access UI-elements. No need to check for InvokeRequired or to call Invoke.
To make your ThreadMethod async:
declare it async
instead of TResults return Task<TResult>; instead of void return Task
only exception: async event handlers return void
whenever you call other methods that have an async version, call this async version, start awaiting when you need the results of the async task.
public async Task FetchCustomerAddress(int customerId)
{
// fetch the customer address from the database:
using (var dbContext = new OrderDbContext(...))
{
return await dbContext.Customers
.Where(customer => customer.Id == customerId)
.Select(customer => new Address
{
Name = customer.Name,
Street = customer.Street,
... // etc
})
.FirstOrDefaultAsync();
}
}
public async Task CreateCustomerOrder(
int customerId, IEnumerable orderLines)
{
// start reading the customer Address
var taskReadCustomerAddress = this.FetchCustomerAddress(customerId);
// meanwhile create the order
CustomerOrder order = new CustomerOrder();
foreach (var orderLine in orderLines)
{
order.OrderLines.Add(orderLine);
}
order.CalculateTotal();
// now you need the address of the customer: await:
Address customerAddress = await taskReadCustomerAddress;
order.Address = customerAddress;
return order;
}
Sometimes you don't have to wait idly for another process to finish, but you need to do some heavy calculations, and still keep your UI-thread responsive. In older applications you would use the BackgroundWorker for this, in newer applications you use Task.StartNew
For instance, you have a button, and a menu item that both will start some heavy calculations. Just like when using the backgroundworker you want to show some progress. While doing the calculations, both the menu item and the button need to be disable.
public async Task PrintCustomerOrdersAsync(
ICollection<CustomerOrderInformation> customerOrders)
{
// while creating the customer orders: disable the button and the menu items
this.buttonPrintOrders.Enabled = false;
this.menuItemCreateOrderLines.Enabled = false;
// show the progress bar
this.ProgressBarCalculating.MinValue = 0;
this.ProgressBarCalculating.MaxValue = customers.Count;
this.ProgressBarCalculating.Value = 0;
this.ProgressBarCalculating.Visible = true;
List<Task<PrintJob>> printJobs = new List<Task<PrintJob>>();
foreach (CustomerOrderInformation orderInformation in customerOrders)
{
// instead of BackGroundworker raise event, you can access the UI items yourself
CustomerOrder order = this.CreateCustomerOrder(orderInformation.CustomerId,
orderInformation.OrderLines);
this.ProgressBarCalculating.Value +=1;
// print the Order, do not await until printing finished, create next order
printJobs.Add(this.Print(order));
}
// all orders created and sent to the printer. await until all print jobs complete:
await Task.WhenAll(printJobs);
// cleanup:
this.buttonPrintOrders.Enabled = true;
this.menuItemCreateOrderLines.Enabled = true;
this.ProgressBarCalculating.Visible = false;
}
By the way: in a proper design, you would separate the enabling / disabling the items from the actual processing:
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
await this.PrintOrdersAsync(customerOrders);
this.HideBusyPrintingOrders();
}
Now to start printing the orders when a button is pressed, there are two possibilities:
If the process is mostly waiting for others: async event handler
If there are really heavy calculations (longer than a second?): start a task that does the calculations
No heavy calculations:
// async event handler has void return value!
private async void ButtonPrintOrdersClickedAsync(object sender, ...)
{
var orderInformations = this.GetOrderInformations();
await PrintCustomerOrdersAsync(orderInformations);
}
Because I don't have anything other useful to do, I await immediately
Heavy calculations: start a separate task:
private async Task ButtonCalculateClickedAsync(object sender, ...)
{
var calculationTask = Task.Run(() => this.DoHeavyCalculations(this.textBox1.Text);
// because you didn't await, you are free to do something else,
// for instance show progress:
while (!calculationTask.Complete)
{
// await one second; UI is responsive!
await Task.Delay(TimeSpan.FromSeconds(1));
this.ProgressBar.Value += 1;
}
}
Be aware: using these methods, you can't stop the process. So you are in trouble if the operator wants to close the application while you are still printing.
Just like your background thread, every method that supports cancellation should regularly check if cancellation is requested. The advantage is, that this checking is also done in the .NET methods that support cancellation, like reading database information, writing a file, etc. The backgroundWorker couldn't cancel writing to a file.
For this we have the CancellationTokenSource
private CancellationTokenSource cancellationTokenSource;
private Task taskPrintOrders;
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
using (this.cancellactionTokenSource = new CancellationTokenSource())
{
taskPrintOrders = this.PrintOrdersAsync(customerOrders, this.cancellationTokenSource.Token);
await taskPrintOrders;
this.HideBusyPrintingOrders();
}
private void CancelPrinting()
{
this.cancellationTokenSource?.Cancel();
}
If you want to cancel and wait until finished, for instance when closing the form:
private bool TaskStillRunning => this.TaskPrinting != null && !this.TaskPrinting.Complete;
private async void OnFormClosing(object sender, ...)
{
if (this.TaskStillRunning)
{
bool canClose = this.AskIfCanClose();
if (!canClose)
eventArgs.Cancel = true;
else
{
// continue closing: stop the task, and wait until stopped
this.CancelPrinting();
await this.taskPrintOrders;
}
}
}
This will work in separate thread without hanging your UI.
Use new Thread
new Thread(delegate()
{
Thread_Method();
}).Start();
or Task.run
Task.Run(() =>
{
Thread_Method();
});

Managing task cancellation and completion on a concurrent thread

[ This question needs to be reimagined. One of my thread queues MUST run on an STA thread, and the code below does not accommodate that. In particular it seems Task<> chooses its own thread and that just is not going to work for me. ]
I have a task queue (BlockingCollection) that I'm running through on a dedicated thread. That queue receives a series of Task<> objects that it runs sequentially within that thread via a while loop.
I need a means of Cancelling that series of tasks, and a means of knowing that the tasks are all complete. I have not been able to figure out how to do this.
Here's a fragment of my queuing class. ProcessQueue is run on a separate thread from main. QueueJob calls occur on the main thread.
using Job = Tuple<Task<bool>, string>;
public class JobProcessor
{
private readonly BlockingCollection<Job> m_queue = new BlockingCollection<Job>();
volatile bool cancel_queue = false;
private bool ProcessQueue()
{
while (true)
{
if (m_queue.IsAddingCompleted)
break;
Job tuple;
if (!m_queue.TryTake(out tuple, Timeout.Infinite))
break;
var task = tuple.Item1;
var taskName = tuple.Item2;
try
{
Console.WriteLine("Task {0}::{1} starting", this.name, taskName);
task.RunSynchronously();
Console.WriteLine("Task {0}::{1} completed", this.name, taskName);
}
catch (Exception e)
{
string message = e.Message;
}
if (cancel_queue) // CANCEL BY ERASING TASKS AND NOT RUNNING.
{
while (m_queue.TryTake(out tuple))
{
}
}
} // while(true)
return true;
}
public Task<bool> QueueJob(Func<bool> input)
{
var task = new Task<bool>(input);
try
{
m_queue.Add(Tuple.Create(task, input.Method.Name));
}
catch (InvalidOperationException)
{
Task<bool> dummy = new Task<bool>(() => false);
dummy.Start();
return dummy;
}
return task;
}
Here are the functions that trouble me:
public void ClearQueue()
{
cancel_queue = true;
// wait for queue to become empty. HOW?
cancel_queue = false;
}
public void WaitForCompletion()
{
// wait for all tasks to be completed.
// not sufficient to wait for empty queue because the last task
// must also execute and finish. HOW?
}
}
Here is some usage:
class SomeClass
{
void Test()
{
JobProcessor jp = new JobProcessor();
// launch Processor loop on separate thread... code not shown.
// send a bunch of jobs via QueueJob... code not show.
// launch dialog... code not shown.
if (dialog_result == Result.Cancel)
jp.ClearQueue();
if (dialog_result == Result.Proceed)
jp.WaitForCompletion();
}
}
The idea is after the work is completed or cancelled, new work may be posted. In general though, new work may come in asynchronously. WaitForCompletion might in fact be "when all work is done, inform the user and then do other stuff", so it doesn't strictly have to be a synchronous function call like above, but I can't figure how to make these happen.
(One further complication, I expect to have several queues that interact. While I am careful to keep things parallelized in a way to prevent deadlocks, I am not confident what happens when cancellation is introduced into the mix, but this is probably beyond scope for this question.)
WaitForCompletion() sounds easy enough. Create a semaphore or event, create a task whose only action is to signal the semaphore, queue up the task, wait on the semaphore.
When the thread finishes the last 'real' task, the semaphore task will be run and so the thread that called WaitForCompletion will become ready/running:)
Would not a similar approach work for cancellation? Have a very high priority thread that you create/signal that drains the queue of all pending jobs, disposing them, queueing up the semaphore task and waiting for the 'last task done' signal?

Run X number of Task<T> at any given time while keeping UI responsive

I have a C# WinForms (.NET 4.5.2) app utilizing the TPL. The tool has a synchronous function which is passed over to a task factory X amount of times (with different input parameters), where X is a number declared by the user before commencing the process. The tasks are started and stored in a List<Task>.
Assuming the user entered 5, we have this in an async button click handler:
for (int i = 0; i < X; i++)
{
var progress = Progress(); // returns a new IProgress<T>
var task = Task<int>.Factory.StartNew(() => MyFunction(progress), TaskCreationOptions.LongRunning);
TaskList.Add(task);
}
Each progress instance updates the UI.
Now, as soon as a task is finished, I want to fire up a new one. Essentially, the process should run indefinitely, having X tasks running at any given time, unless the user cancels via the UI (I'll use cancellation tokens for this). I try to achieve this using the following:
while (TaskList.Count > 0)
{
var completed = await Task.WhenAny(TaskList.ToArray());
if (completed.Exception == null)
{
// report success
}
else
{
// flatten AggregateException, print out, etc
}
// update some labels/textboxes in the UI, and then:
TaskList.Remove(completed);
var task = Task<int>.Factory.StartNew(() => MyFunction(progress), TaskCreationOptions.LongRunning);
TaskList.Add(task);
}
This is bogging down the UI. Is there a better way of achieving this functionality, while keeping the UI responsive?
A suggestion was made in the comments to use TPL Dataflow but due to time constraints and specs, alternative solutions are welcome
Update
I'm not sure whether the progress reporting might be the problem? Here's what it looks like:
private IProgress<string> Progress()
{
return new Progress<string>(msg =>
{
txtMsg.AppendText(msg);
});
}
Now, as soon as a task is finished, I want to fire up a new one. Essentially, the process should run indefinitely, having X tasks running at any given time
It sounds to me like you want an infinite loop inside your task:
for (int i = 0; i < X; i++)
{
var progress = Progress(); // returns a new IProgress<T>
var task = RunIndefinitelyAsync(progress);
TaskList.Add(task);
}
private async Task RunIndefinitelyAsync(IProgress<T> progress)
{
while (true)
{
try
{
await Task.Run(() => MyFunction(progress));
// handle success
}
catch (Exception ex)
{
// handle exceptions
}
// update some labels/textboxes in the UI
}
}
However, I suspect that the "bogging down the UI" is probably in the // handle success and/or // handle exceptions code. If my suspicion is correct, then push as much of the logic into the Task.Run as possible.
As I understand, you simply need a parallel execution with the defined degree of parallelization. There is a lot of ways to implement what you want. I suggest to use blocking collection and parallel class instead of tasks.
So when user clicks button, you need to create a new blocking collection which will be your data source:
BlockingCollection<IProgress> queue = new BlockingCollection<IProgress>();
CancellationTokenSource source = new CancellationTokenSource();
Now you need a runner that will execute your in parallel:
Task.Factory.StartNew(() =>
Parallel.For(0, X, i =>
{
foreach (IProgress p in queue.GetConsumingEnumerable(source.Token))
{
MyFunction(p);
}
}), source.Token);
Or you can choose more correct way with partitioner. So you'll need a partitioner class:
private class BlockingPartitioner<T> : Partitioner<T>
{
private readonly BlockingCollection<T> _Collection;
private readonly CancellationToken _Token;
public BlockingPartitioner(BlockingCollection<T> collection, CancellationToken token)
{
_Collection = collection;
_Token = token;
}
public override IList<IEnumerator<T>> GetPartitions(int partitionCount)
{
throw new NotImplementedException();
}
public override IEnumerable<T> GetDynamicPartitions()
{
return _Collection.GetConsumingEnumerable(_Token);
}
public override bool SupportsDynamicPartitions
{
get { return true; }
}
}
And runner will looks like this:
ParallelOptions Options = new ParallelOptions();
Options.MaxDegreeOfParallelism = X;
Task.Factory.StartNew(
() => Parallel.ForEach(
new BlockingPartitioner<IProgress>(queue, source.Token),
Options,
p => MyFunction(p)));
So all you need right now is to fill queue with necessary data. You can do it whenever you want.
And final touch, when the user cancels operation, you have two options:
first you can break execution with source.Cancel call,
or you can gracefully stop execution by marking collection complete (queue.CompleteAdding), in that case runner will execute all already queued data and finish.
Of course you need additional code to handle exceptions, progress, state and so on. But main idea is here.

Random tasks from Task.Factory.StartNew never finishes

I am using Async await with Task.Factory method.
public async Task<JobDto> ProcessJob(JobDto jobTask)
{
try
{
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
await T;
}
This method I am calling inside a loop like this
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
What I notice is that new tasks opens up inside Process explorer and they also start working (based on log file). however out of 10 sometimes 8 or sometimes 7 finishes. Rest of them just never come back.
why would that be happening ?
Are they timing out ? Where can I set timeout for my tasks ?
UPDATE
Basically above, I would like each Task to start running as soon as they are called and wait for the response on AWAIT T keyword. I am assuming here that once they finish each of them will come back at Await T and do the next action. I am alraedy seeing this result for 7 out of 10 tasks but 3 of them are not coming back.
Thanks
It is hard to say what the issues is without the rest if the code, but you code can be simplified by making ProcessJob synchronous and then calling Task.Run with it.
public JobDto ProcessJob(JobDto jobTask)
{
JobWorker jobWorker = new JobWorker();
return jobWorker.Execute(jobTask);
}
Start tasks and wait for all tasks to finish. Prefer using Task.Run rather than Task.Factory.StartNew as it provides more favourable defaults for pushing work to the background. See here.
for(int i=0; i < jobList.Count(); i++)
{
tasks[i] = Task.Run(() => ProcessJob(jobList[i]));
}
try
{
await Task.WhenAll(tasks);
}
catch(Exception ex)
{
// handle exception
}
First, let's make a reproducible version of your code. This is NOT the best way to achieve what you are doing, but to show you what is happening in your code!
I'll keep the code almost same as your code, except I'll use simple int rather than your JobDto and on completion of the job Execute() I'll write in a file that we can verify later. Here's the code
public class SomeMainClass
{
public void StartProcessing()
{
var jobList = Enumerable.Range(1, 10).ToArray();
var tasks = new Task[10];
//[1] start 10 jobs, one-by-one
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
//[4] here we have 10 awaitable Task in tasks
//[5] do all other unrelated operations
Thread.Sleep(1500); //assume it works for 1.5 sec
// Task.WaitAll(tasks); //[6] wait for tasks to complete
// The PROCESS IS COMPLETE here
}
public async Task ProcessJob(int jobTask)
{
try
{
//[2] start job in a ThreadPool, Background thread
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
});
//[3] await here will keep context of calling thread
await T; //... and release the calling thread
}
catch (Exception) { /*handle*/ }
}
}
public class JobWorker
{
static object locker = new object();
const string _file = #"C:\YourDirectory\out.txt";
public void Execute(int jobTask) //on complete, writes in file
{
Thread.Sleep(500); //let's assume does something for 0.5 sec
lock(locker)
{
File.AppendAllText(_file,
Environment.NewLine + "Writing the value-" + jobTask);
}
}
}
After running just the StartProcessing(), this is what I get in the file
Writing the value-4
Writing the value-2
Writing the value-3
Writing the value-1
Writing the value-6
Writing the value-7
Writing the value-8
Writing the value-5
So, 8/10 jobs has completed. Obviously, every time you run this, the number and order might change. But, the point is, all the jobs did not complete!
Now, if I un-comment the step [6] Task.WaitAll(tasks);, this is what I get in my file
Writing the value-2
Writing the value-3
Writing the value-4
Writing the value-1
Writing the value-5
Writing the value-7
Writing the value-8
Writing the value-6
Writing the value-9
Writing the value-10
So, all my jobs completed here!
Why the code is behaving like this, is already explained in the code-comments. The main thing to note is, your tasks run in ThreadPool based Background threads. So, if you do not wait for them, they will be killed when the MAIN process ends and the main thread exits!!
If you still don't want to await the tasks there, you can return the list of tasks from this first method and await the tasks at the very end of the process, something like this
public Task[] StartProcessing()
{
...
for (int i = 0; i < jobList.Count(); i++)
{
tasks[i] = ProcessJob(jobList[i]);
}
...
return tasks;
}
//in the MAIN METHOD of your application/process
var tasks = new SomeMainClass().StartProcessing();
// do all other stuffs here, and just at the end of process
Task.WaitAll(tasks);
Hope this clears all confusion.
It's possible your code is swallowing exceptions. I would add a ContineWith call to the end of the part of the code that starts the new task. Something like this untested code:
var T = Task.Factory.StartNew(() =>
{
JobWorker jobWorker = new JobWorker();
jobWorker.Execute(jobTask);
}).ContinueWith(tsk =>
{
var flattenedException = tsk.Exception.Flatten();
Console.Log("Exception! " + flattenedException);
return true;
});
},TaskContinuationOptions.OnlyOnFaulted); //Only call if task is faulted
Another possibility is that something in one of the tasks is timing out (like you mentioned) or deadlocking. To track down whether a timeout (or maybe deadlock) is the root cause, you could add some timeout logic (as described in this SO answer):
int timeout = 1000; //set to something much greater than the time it should take your task to complete (at least for testing)
var task = TheMethodWhichWrapsYourAsyncLogic(cancellationToken);
if (await Task.WhenAny(task, Task.Delay(timeout, cancellationToken)) == task)
{
// Task completed within timeout.
// Consider that the task may have faulted or been canceled.
// We re-await the task so that any exceptions/cancellation is rethrown.
await task;
}
else
{
// timeout/cancellation logic
}
Check out the documentation on exception handling in the TPL on MSDN.

Task.Factory.StartNew depend on parent thread?

I'm running this thread inside a method from a WCF service library.
The code below is executed at the end of the method. I do this because i don't want the user to wait for a background process to complete that does not affect the output from the WCF to the client.
The problem that i have now is that if i execute that thread and the client gets the response, the parent thread is killed; killing this thread as well. How do i make it so that the parent thread waits for this thread to finish, while performing the rest of the operations?
class Program
{
static void Main(string[] args)
{
Dictionary<string, string> sampleDict = getPopulatedDictionary();
var result = run(sampleDict);
}
public static int run(Dictionary<string, string> sampleDict_)
{
PerformCalculations(sampleDict_);
if (sampleDict_.Keys.Count > 10)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
backgroundprocess(sampleDict_);
});
}
//after returning i still want it to run
return sampleDict_.Keys.Count;
}
private static void backgroundprocess(Dictionary<string,string> dict)
{
foreach (var k in dict.Keys)
{
dict[k] = new Random().Next(2666).ToString();
}
}
}
In short, i want this method to kick off that thread and move onto return the value X but still wait for that thread to finish AFTER it returns the value.
Couldn't you do it as a continuation of the parent task. So execute
FameMappingEntry.SaveFameDBMap(toSaveIdentifiers); as a continuation of a successful completion of the parent task. And then you can wait on the continutation.
var childTask = parentTask.ContinueWith((pt) =>
{
FameMappingEntry.SaveFameDBMap(toSaveIdentifiers);
}, TaskContinuationOptions.OnlyOnRanToCompletion);
And then you can decide if you want to wait on the child task or use another continuation.
If you aren't going to do anything except wait for the background thread to complete, then you might as well just not create the new background thread in the first place and execute the code in-line.
Try this:
var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
lock (toSaveIdentifiers)
{
FameMappingEntry.SaveFameDBMap(toSaveIdentifiers);
}
);
int x = dosomething();
task.Wait();
return x;
You should also lock objects in the thread that uses them, and not some other random thread.

Categories

Resources