This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 13 days ago.
Very new to async programming and trying to test some things. Any clue what I need to do to ensure that my Debug.WriteLine() statements will print the "correct" value for "i" (from my original loop)? The below attempt (of assigning to x and passing that value down to my async method) didnt work (as i never get a 0 value and then usually get the last value, 5, repeated several times). Ive seen some posts about lock () and tried wrapping the assignment to x in it, but I clearly dont understand exactly how that works, and it didnt seem to in this case. TIA
private async void btnStart_Click(object sender, EventArgs e)
{
var tskDataSetCodes = new List<Task>();
Stopwatch s = new Stopwatch();
int x = 99;
for (int i = 0; i < 6; i++)
{
x = i;
s.Start();
Task kickoffTasks = new Task(() => ExtractDataSetCode(x));
System.Diagnostics.Debug.WriteLine("DataSet : " + x + "Task: " + kickoffTasks.Id);
kickoffTasks.Start();
tskDataSetCodes.Add(kickoffTasks);
}
await Task.WhenAll(tskDataSetCodes);
s.Stop();
var tasktime = s.ElapsedMilliseconds;
System.Diagnostics.Debug.WriteLine("Application Completed" + tasktime);
}
static async void ExtractDataSetCode(int a)
{
System.Diagnostics.Debug.WriteLine("ExtractDataSetCode: " + a + " on thread: " + Thread.CurrentThread.ManagedThreadId);
var tasks = new List<Task>();
for (var count = 1; count <= 10; ++count)
{
Task queryTasks = new Task(() => queryProcess(a), TaskCreationOptions.AttachedToParent);
queryTasks.Start();
tasks.Add(queryTasks);
}
await Task.WhenAll(tasks);
}
static void queryProcess(int z)
{
System.Diagnostics.Debug.WriteLine("Starting queryProcess for dataset: " + z + " on thread: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10000);
//System.Diagnostics.Debug.WriteLine("Ending queryProcess for dataset: " + i + " on thread: " + Thread.CurrentThread.ManagedThreadId);
}
x here is "captured", meaning the same variable is used by all instances of the loop - with the value being a race condition between the loop and the task execution; move it inside the loop:
for (int i = 0; i < 6; i++)
{
int x = i;
// ...
}
You might also want to use Task.Run instead of new() and Start():
s.Start();
for (int i = 0; i < 6; i++)
{
int x = i;
tskDataSetCodes.Add(Task.Run(() => ExtractDataSetCode(x)));
}
Related
so I'm in a bit confused as to how I'm supposed to do something. I've got 5 threads that are doing a basic task and they are generated with a for loop in main. I've already used a semaphore that limits the amount of threads running at a time as that's a part of the exercise, what I've got left is to make sure that threads that are next to each other (they're numbered 0-4 using the loop) don't run simultaneously. What I've got as an idea is to block every odd or even thread(it doesn't really matter) but I can't figure out how to both let two threads in and at the same time block every odd one. Is there a specific method for that, or maybe if there is another way, like letting three in at first and somehow not letting the second one in but letting the third one. I'll leave what I've got done so far:
edit: For clarification the way it has to be thought about is actually a bit different then what I initially asked about. So if 1 is running both 0 and 2 aren't allowed to run. But if 0 is running both 4 and 1 aren't allowed to run either. I'm pretty sure that it's obvious that if 4 is running 0 and 3 aren't allowed to work etc. .
using System.Threading;
namespace StudentProblem
{
public class StudentProblem
{
static Semaphore stop = new Semaphore(2,2);
static Semaphore gate = new Semaphore(3,3);
public static void Student(Object o)
{
var r = new Random();
var num = (int) o;
while (true)
{
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
//gate.WaitOne();
stop.WaitOne();
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(2000, 3000));
for (int i = 0; i < num; i++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
//gate.Release();
stop.Release();
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
studentThreads[i] = new Thread(StudentProblem.Student);
studentThreads[i].Start(i);
}
}
}
}
In the end I decided to ditch the whole multiple semaphore approach and went with the old and trusty way. I'll add my solution here. It's not that great, but it works.
using System;
using System.Collections.Generic;
using System.Threading;
namespace testing
{
public class StudentProblem
{
public static List<StudentProblem> allProblems = new List<StudentProblem>();
static Semaphore eatingGate = new Semaphore(2, 2);
private object id;
private bool eating = false;
public StudentProblem(object o)
{
id = o;
}
public object Id
{
get
{
return this.id;
}
}
public bool Eating
{
get
{
return this.eating;
}
}
public void DoStuff()
{
var r = new Random();
var num = (int)this.Id;
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
while (true)
{
for (int i = 0; i < num; i++)
Console.Write("_");
int indexBehind = 0;
int indexFront = 0;
for (int i = 0; i < allProblems.Count; i++)
{
if(num == 0)
{
indexBehind = 4;
}
else
{
indexBehind = num - 1;
}
if(num == 4)
{
indexFront = 0;
}
else
{
indexFront = num + 1;
}
check:
if (allProblems[indexBehind].Eating != true && allProblems[indexFront].Eating != true)
{
if (eatingGate.WaitOne())
{
this.eating = true;
Thread.Sleep(250);//poigrai si s timeout-a
Console.WriteLine("> Student " + num + " start eating.");
Thread.Sleep(r.Next(1000, 2000));
for (int j = 0; j < num; j++)
Console.Write("_");
Console.WriteLine("< Student " + num + " stop eating");
this.eating = false;
eatingGate.Release();
Console.WriteLine(" Student " + num + " start learning.");
Thread.Sleep(r.Next(2000, 3000));
}
else
{
goto check;
}
}
else
{
goto check;
}
}
}
}
}
class Program
{
static void Main(string[] args)
{
var studentThreads = new Thread[5];
for (int i = 0; i < 5; i++)
{
StudentProblem.allProblems.Add(new StudentProblem(i));
studentThreads[i] = new Thread(StudentProblem.allProblems[i].DoStuff);
studentThreads[i].Start();
}
}
}
}
I am a novice in C#/.NET. Here I am trying to run the following parallel tasks and measure the total execution time.
But after running the code the execution time is showing just > 6 ms which is way less than it is supposed to be. I am not sure if there is any misplacing of the Stopwatch() function that's giving this unexpected result.
Your help will be appreciated :
namespace Tests
{
class Prod
{
static void Main(string[] args)
{
Stopwatch s = new Stopwatch();
s.Start();
{
Task T1 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test1:" + i);
});
Task T2 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test2:" + i);
});
Task T3 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test3:" + i);
});
}
s.Stop();
Console.WriteLine("Press any key to quit");
Console.ReadKey();
Console.WriteLine("Total Task Ellapsed time -> {0}", s.ElapsedMilliseconds);
}
}
}
You need a Task.WaitAll before the stop of the Stopwatch (s.Stop() in your code)
for example:
Task.WaitAll(T1,T2,T3);
s.Stop();
One solution would be to wait for all Tasks to be completed using Task.WaitAll
Task.WaitAll(T1,T2,T3);
Complete Code
Stopwatch s = new Stopwatch();
s.Start();
{
Task T1 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test1:" + i);
});
Task T2 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test2:" + i);
});
Task T3 = Task.Run(() =>
{
for (int i = 0; i <= 5000; i++)
Console.WriteLine("Test3:" + i);
});
Task.WaitAll(T1,T2,T3); // Change here
}
s.Stop();
Console.WriteLine("Press any key to quit");
Console.WriteLine("Total Task Ellapsed time -> {0}", s.ElapsedMilliseconds);
This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 11 months ago.
My program is running tasks in groups of n tasks at once each time.
Each task writes data to a Queue<string> object of his own, provided by an index to a Queue<string> in a List<Queue<string>> of queues.
the tasks do not share data or Queues, yet I still get synchronization errors.
I know the data structures are not Thread-Safe, I don't understand why they should be, and why I get the errors, since each Task has his own data structure, what could cause the errors?
here is a simple code to demonstrate:
class Program
{
static int j = 0;
List<Queue<string>> queueList = new List<Queue<string>>();
public void StartTasts(int n)
{
for (int i = 0; i < n; i++)
queueList.Add(new Queue<string>());
List<Task> tsk = new List<Task>();
for (int TaskGroup = 0; TaskGroup < 10; TaskGroup++)
{ //10 groups of task
//each group has 'n' tasks working in parallel
for (int i = 0; i < n; i++)
{
//each task gets its own and independent queue from the list
tsk.Add(Task.Factory.StartNew(() =>
{
DoWork(j % n);
}));
j++;
}
//waiting for each task group to finish
foreach (Task t in tsk)
t.Wait();
//after they all finished working with the queues, clear queues
//making them ready for the nest task group
foreach (Queue<string> q in queueList)
q.Clear();
}
}
public void DoWork(int queue)
{
//demonstration of generating strings
//and put them in the correct queue
for (int k = 0; k < 10000; k++)
queueList[queue].Enqueue(k + "");
}
static void Main(string[] args)
{
new Program().StartTasts(10);
}
}
this program generate some errors such as:
System.ArgumentException: 'Destination array was not long enough. Check destIndex and length, and the array's lower bounds.'
System.IndexOutOfRangeException: 'Index was outside the bounds of the array.' (at the Queue)
System.AggregateException: One or more errors occurred. ---> System.ArgumentException: Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
and more errors and would not come up on a Serial case.
I would love to understand why because I cant see how these tasks mess up each other's independent Queues.
The problem is normal variable closure issues. Because all tasks share the same instance of the variable j they will all share the same value, most likely what is happening is your loop starts up 10 tasks super quick, but before any of them can get to j % n the value of j has already become 10.
Make a local copy of k that is declared within the scope of the for loop and it should solve your problem.
public void StartTasts(int n)
{
for (int i = 0; i < n; i++)
queueList.Add(new Queue<string>());
List<Task> tsk = new List<Task>();
for (int TaskGroup = 0; TaskGroup < 10; TaskGroup++)
{ //10 groups of task
//each group has 'n' tasks working in parallel
for (int i = 0; i < n; i++)
{
int k = j; // `int k = i;` would work here too and give you the same results.
tsk.Add(Task.Factory.StartNew(() =>
{
DoWork(k % n);
}));
j++;
}
//waiting for each task group to finish
foreach (Task t in tsk)
t.Wait();
//after they all finished working with the queues, clear queues
//making them ready for the nest task group
foreach (Queue<string> q in queueList)
q.Clear();
}
}
If you want to see the problem in action with a simpler recreation, try this simple code instead.
public static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
int j = i;
Task.TaskFactory.StartNew(() =>
{
Thread.Sleep(10); //Give a little time for the for loop to complete.
Console.WriteLine("i: " + i + " j: " + j);
}
});
Console.ReadLine();
}
You have calculated the taskId inside of the task and changed the base for the calculation outside of the task.
I have changed the logic only slightly. I have not had any errors.
namespace Project1
{
using System.Collections.Generic;
using System.Threading.Tasks;
internal class Program
{
private static int j = 0;
private readonly List<Queue<string>> queueList = new List<Queue<string>>();
public void StartTasts(int n)
{
for (var i = 0; i < n; i++)
{
this.queueList.Add(new Queue<string>());
}
var taskList = new List<Task>();
for (var taskGroup = 0; taskGroup < 10; taskGroup++)
{
// 10 groups of task
// each group has 'n' tasks working in parallel
for (var i = 0; i < n; i++)
{
// each task gets its own and independent queue from the list
var taskId = j % n;
taskList.Add(
Task.Factory.StartNew(
() =>
{
this.DoWork(taskId);
}));
j++;
}
// waiting for each task group to finish
foreach (var t in taskList)
{
t.Wait();
}
// after they all finished working with the queues, clear queues
// making them ready for the nest task group
foreach (var q in this.queueList)
{
q.Clear();
}
}
}
public void DoWork(int queue)
{
// demonstration of generating strings
// and put them in the correct queue
for (var k = 0; k < 10000; k++)
{
this.queueList[queue].Enqueue(k + string.Empty);
}
}
private static void Main(string[] args)
{
new Program().StartTasts(10);
}
}
}
I do not think you problem is in the que, it seems like it in the list itself might be an issue.
As the rule of using parallel or synchronous processes the list is not a thread save DS.
Try using the thread save DS Like ConcurrentBag Class
This question already has an answer here:
Only last task runs!
(1 answer)
Closed 6 years ago.
I am trying to understand how I might be able to make better use of the .Net 4.5 TPL. Traditionally I used to manage the threads the old-school way, queueing and managing the threads directly.
I have created a silly program to explore the TPL, however, the code only seems to execute the last of the tasks added to my tasks list - I cannot determine why:
class Program {
static void Main(string[] args) {
var a = new A();
var b = new B();
var tasks = new List<Task<string>>();
for (int j = 33; j < 64; j++) {
tasks.Add(Task.Run(() => a.Go(j, 20)).ContinueWith((i) => b.Do(i)));
}
var finalTask = Task.Factory.ContinueWhenAll(tasks.ToArray(), r => {
foreach (var t in r)
Console.Write(t.Result);
});
finalTask.Wait();
Console.WriteLine("Finished.");
Console.ReadLine();
}
}
public class A {
public int Go(int chr, int loops) {
for (int i = 0; i < loops; i++) {
Thread.Sleep(10);
Console.Write((char)chr);
}
return loops;
}
}
public class B {
public string Do(Task<int> value) {
string s = "";
for (int i = 0; i < value.Result; i++) {
s = s + "a";
}
return s;
}
}
Any ideas why the other threads do not execute?
You have to capture the running variable j within the closure context:
for (int j = 33; j < 64; j++) {
var num = j;
tasks.Add(Task.Run(() => a.Go(num, 20)).ContinueWith((i) => b.Do(i)));
}
See also Captured variable in a loop in C#
I've got the following multithreaded code for calculating Euler's number. I'm new in multithreaded programming and maybe I'm missing something. For some reason countdown.Wait() is not waiting for all the threads and totalSum is different almost every time. It looks like it skips some of the intermediate sums.
public static class Program
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
private static CountdownEvent countDown = new CountdownEvent(threadsCount);
private static Object locker = new Object();
private static void Main(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateEulerNumber), threadIndex);
}
countDown.Wait();
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static void CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
totalSum = BigRational.Add(totalSum, sum);
stopwatch.Stop();
lock (locker)
{
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToDecimalString(40));
}
Console.WriteLine();
}
countDown.Signal();
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
#usr made a good point: you better use ConcurrentStack<T> or ConcurrentQueue<T> as detailed in http://msdn.microsoft.com/en-us/library/system.collections.concurrent%28v=vs.110%29.aspx.
Also, it's better to implement your algorithm using Task.Factory as explained by Alexandra Rusina in http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx. As per the mentioned resources, your solution may look like something following (giving you general idea)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
ConcurrentStack<int> cs = new ConcurrentStack<int>();
public static double YourFunction(int SomeNumber)
{
// computation of result
return result;
}
private void start_Click(object sender, RoutedEventArgs e)
{
textBlock1.Text = "";
label1.Content = "Milliseconds: ";
var watch = Stopwatch.StartNew();
List<Task> tasks = new List<Task>();
for (int i = 2; i < 20; i++)
{
int j = i;
var t = Task.Factory.StartNew(() =>
{
int result = YourFunctiopn(j);
this.Dispatcher.BeginInvoke(new Action(() =>
cs.Add(result ))
, null);
});
tasks.Add(t);
}
Task.Factory.ContinueWhenAll(tasks.ToArray(),
result =>
{
var time = watch.ElapsedMilliseconds;
this.Dispatcher.BeginInvoke(new Action(() =>
label1.Content += time.ToString()));
});
}
}
Hope this will help. Rgds,
You are using the CountDownEvent wrongly.CountDownEvent are for signalling and you dont need this in current program. You can do this with tasks:
public class Class1
{
private static int elementsCount = 500;
private static int threadsCount = 20;
private static string outputFileName = "defaultFileName.txt";
private static bool isInQuietMode = false;
private static BigRational totalSum = new BigRational(0.0m);
public static void Main1(string[] args)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
List<Task<BigRational>> tasks = new List<Task<BigRational>>();
//Create the tasks
for (int threadIndex = 0; threadIndex < threadsCount; threadIndex++)
{
Task<BigRational> task = new Task<BigRational>((data)=>
{
return CalculateEulerNumber(data);
},threadIndex);
tasks.Add(task);
}
foreach (var task in tasks)
{
task.Start();
}
//Wait for tasks
Task.WaitAll(tasks.ToArray());
//Add the results
foreach (var task in tasks)
{
totalSum = BigRational.Add(totalSum, task.Result);
}
File.WriteAllText(outputFileName, "Euler's number: " + totalSum);
stopwatch.Stop();
Console.WriteLine("Result: ");
Console.WriteLine("Total time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Euler's number - " + totalSum);
}
}
private static BigRational CalculateEulerNumber(object threadIndexObject)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
int threadIndex = Convert.ToInt32(threadIndexObject);
BigRational sum = new BigRational(0.0m);
for (int k = threadIndex; k < elementsCount; k += threadsCount)
{
BigRational numerator = BigRational.Pow((3 * k), 2) + 1;
BigRational denominator = Factorial(3 * k);
sum += BigRational.Divide(numerator, denominator);
}
stopwatch.Stop();
int threadNumber = threadIndex + 1;
Console.WriteLine("Тhread " + threadNumber + ": ");
Console.WriteLine("Time elapsed - " + stopwatch.Elapsed);
if (!isInQuietMode)
{
Console.WriteLine("Intermediate sum - " + sum.ToString());
}
Console.WriteLine();
return sum;
}
private static BigRational Factorial(int n)
{
BigRational factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
return factorial;
}
}
So create the task and each task can run seperately and return individual sum. You can then add the results to create the total sum. There is no need of locks either.