C# Threading inside for loop [duplicate] - c#

This question already has answers here:
Waiting for all threads to complete, with a timeout
(10 answers)
Closed 6 years ago.
I want the for loop to complete before I print the result, in:
for (int i = 0; i < 5; i++)
{
(new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
})).Start();
}
Console.WriteLine("Count = " + nResult);
but Console.WriteLine will not wait for those threads to finish because printing is done on the main thread.
If I change it to:
System.Threading.Thread t = new System.Threading.Thread(() =>
{
for (int i = 0; i < 5; i++)
{
(new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
})).Start();
}
});
t.Start();
t.Join();
Console.WriteLine("Count = " + nResult);
it will still not solve the problem because the nested threads will not be waited for.
Any simple solution to this? Thanks for going through this.

You should store the created threads to control them, I used a List.
int nResult = 0;
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 5; i++)
{
Thread thread = new System.Threading.Thread(() =>
{
if (TimeTakingMethod())
{
++nResult;
}
});
thread.Start();
threads.Add(thread);
}
foreach (Thread thread in threads)
thread.Join();
Console.WriteLine("Count = " + nResult);

An example of how you could do this:
int result = 0;
Task.WaitAll(Enumerable.Range(0, 5)
.Select(index => Task.Factory.StartNew(() =>
{
// Do thread things...
Interlocked.Increment(ref result);
})).ToArray());
Console.WriteLine(result);
The two important things to note are Task.WaitAll which will cause the program to wait for all tasks to complete before moving on to the WriteLine call.
Also Interlocked.Increment will allow you to safely increment result from any thread.

Related

Does maxDegreeOfParallelism stop every other Parallel.ForEach from doing creating new tasks?

If there are two Parallel.ForEach loops with maxDegreOfParallelism = 3, will both only run 3 threads?
OR
Can we restrict the number of threads are generated to a specific number?
I have a code in which I require Parallel.ForEach twice, they only have a task.Start() call.
My question is if I specify in both Parallel.ForEach loops that maxDegreeOfParallelism = 3, does that apply in general? That is, will the other Parallel.ForEach not invoke an action if already 3 threads will be running?
This is just a demo type code, not the real thing. For reasons, I'd prefer not to share the actual function. Only the subTasks.Add(() => {}) portion is different, rest is the same.
async static void myFunction()
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
int m = i + 1;
List<Task> subTasks = new List<Task>();
for (int j = 0; j < 3; j++)
{
int n = j + 1;
subTasks.Add(new Task(async () => {
//the actual work i want done will go in here
Console.WriteLine("Executing Task " + m + "." + n);
await Task.Delay(5000);
Console.WriteLine("Completed Task " + m + "." + n);
}));
}
tasks.Add(new Task(async () => {
Console.WriteLine("Executing Task " + m);
Parallel.ForEach(subTasks, new ParallelOptions() { MaxDegreeOfParallelism = 3 },
subTask => {
subTask.Start();
});
await Task.WhenAll(subTasks);
Console.WriteLine("Completed Task " + m);
}));
}
Parallel.ForEach(tasks, new ParallelOptions() { MaxDegreeOfParallelism = 3 }, task => { task.Start(); });
await Task.WhenAll(tasks);
}
I want the Parallel.ForEach loop to not invoke more actions if a total of 3 threads are running.
Also, if there is an alternate way of doing this, I'll be grateful if anyone could help.

Thread start passed integer changes itself beyond what it should be [duplicate]

This question already has an answer here:
Thread alters passed Int, if start() is called separately
(1 answer)
Closed 7 years ago.
I have no idea what is going on in this. I'm trying to test thread safety of a class by spawning 100 threads to access it constantly, but it seems my anonymous method parameters are changing themselves to values they should never be and I'm confused as to why. As I have no idea what's going on, I'll just post all the functions involved in testing. Somehow I'm ending up with "Thread 98" getting the parameter "num = 100"... That shouldn't be possible and I have no idea what kind of hokey pokey is going on that is changing the integer. (in method "ThreadWriting(int num)" you'll see the point where I check for "num" to equal 100, where I put a break point to catch the offending thread in the act, and it breaks every time. Otherwise it throws an "IndexOutofRangeException" on the array "counts". I'm just trying to see if my threads are generally getting equal access to the class they're all trying to use at once.
public delegate void TempDel();
public TempDel InvokeTest;
public void TRTest3(Form1 sender)
{
InvokeTest = new TempDel(UpdateInvoke);
Thread t = new Thread(() => ConsoleUpdateTest(sender));
t.IsBackground = true;
t.Start();
POConsole.Instance.MaxLines = 20;
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
}
public ulong[] counts = new ulong[100];
public void ThreadWriting(int num)
{
if(num == 100)
{
bool stop = true;
}
while (true)
{
POConsole.Instance.WriteLine("Hello from Thread " + num);
counts[num]++;
}
}
public void ConsoleUpdateTest(Form1 sender)
{
while(true)
{
sender.Invoke(InvokeTest);
Thread.Sleep(5);
}
}
public void UpdateInvoke()
{
QuickTestBox.Text = POConsole.Instance.FullFeed;
}
All my threads are named, as you can see, and none of them receives the name "Thread 100" so I have no idea how one of the other threads could get passed a parameter of 100 or the parameter could be corrupted in some way.
Apparently my thread-safety checking isn't thread safe in some way?
This is a simple closure issue, you should not be using the for loop counter as a threading parameter issue, issue happens out here, for loop and thread execution do not run at same speed, so value of i can change for multiple threads:
for(int i = 0; i < 100; i++)
{
Thread t2 = new Thread(() => ThreadWriting(i));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", i);
t2.Start();
}
Use following modification, create a local variable from loop counter
for(int i = 0; i < 100; i++)
{
int j = i;
Thread t2 = new Thread(() => ThreadWriting(j));
t2.IsBackground = true;
t2.Name = String.Format("Thread {0}", j);
t2.Start();
}

What's the proper way to wait on a Semaphore?

I thought that the following code would let all the 10 threads run, two at a time, and then print "done" after Release() is called 10 times. But that's not what happened:
int count = 0;
Semaphore s = new Semaphore(2, 2);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(new ThreadStart(delegate()
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
s.Release();
}));
t.Start(x);
}
WaitHandle.WaitAll(new WaitHandle[] { s });
Console.WriteLine("done: {0}", count);
output:
done: 6
If the only way to implement the functionality I'm looking for is to pass an EventWaitHandle to each thread and then do a WaitAll() on an array of those EventWaitHandles, then what's the meaning of doing a WaitAll() on an array of only a semaphore? In other words, when does the waiting thread unblock?
WaitHandle.WaitAll just waits until all the handlers are in signalled state.
So when you call WaitHandle.WaitAll on one WaitHandle it works the same as you call s.WaitOne()
You can use, for example, the following code to wait for all the started threads, but allow two threads to run in parallel:
int count = 0;
Semaphore s = new Semaphore(2, 2);
AutoResetEvent[] waitHandles = new AutoResetEvent[10];
for (int x = 0; x < 10; x++)
waitHandles[x] = new AutoResetEvent(false);
for (int x = 0; x < 10; x++)
{
Thread t = new Thread(threadNumber =>
{
s.WaitOne();
Thread.Sleep(1000);
Interlocked.Increment(ref count);
waitHandles[(int)threadNumber].Set();
s.Release();
});
t.Start(x);
}
WaitHandle.WaitAll(waitHandles);
Console.WriteLine("done: {0}", count);
WaitHandle.WaitAll(new WaitHandle[] { s }); waits just like s.WaitOne();. It enters at the first opportunity. You seem to expect this call to wait for all other semaphore operations but there is no way the operating system can tell the difference. This command might well be the first that is granted access to the semaphore.
I think what you need is the Barrier class. It is made for fork-join-style parallelism.

Task usually does not run

I am newbie to parallel programming. I write the basic code below but it doesnt run always as I excepted.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.WriteLine ("End");
I usually could not get the result of the loop 8-9 out of 10 trials. Sometimes it prints the loop results, sometimes not. But I it always prints the Start and End. Whats happening at the behind side ? Why sometimes I could not get the result of loop from time to time ?
Thanks in advance,
Your program is terminating before the parallel loop gets a chance to print any output.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
Console.ReadLine();
Console.WriteLine("End");
Pause by waiting for input, and you'll see the loop run correctly.
Add a readline at the end. You will see the following:
Start
End
0
1
2
3
4
Console.WriteLine("Start");
Task task = Task.Factory.StartNew(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
});
Console.WriteLine("End");
Console.ReadLine();
You must tell your main thread to wait till your task is over.
Your "End" was being printed in most cases before the task thread executed. Use TaskContinuationOptions to tell the parent thread to wait for its tasks threads to complete.
Console.WriteLine ("Start");
Task task = Task.Factory.StartNew(() => {
for (int i = 0; i < 5; i++)
{
Console.WriteLine (i);
}
});
task.ContinueWith(ant =>
{
Console.WriteLine("End");
}, TaskContinuationOptions.NotOnFaulted| TaskContinuationOptions.AttachedToParent);
task.Wait();

When All Threads Are Complete

This is my first real attempt at using multithreading, I want to know how I can tell when all of my tasks groups are done running:
for (int i = 0; i < taskGroups.Count(); i++) {
ThreadStart t = delegate { RunThread(taskGroups[i]); };
new Thread(t).Start();
}
if(allThreadsComplete){ //???
}
Any help would be much appreciated
Addendum:
ThreadStart[] threads = new ThreadStart[taskGroups.Count()];
for (int i = 0; i < taskGroups.Count(); i++) {
threads[i] = new ThreadStart[]
threads[i] = delegate { RunThread(taskGroups[i]); };
new Thread(t).Start();
}
bool threadsComplete = false;
while(!threadsComplete){
for(int i=0;i<taskGroups.Count();i++){
if(threads[i].State == complete)
threadsComplete = true;
}
}
You need to store all your threads, and then call Thread.Join().
Something like this:
List<Thread> threads = new List<Thread>();
for (int i = 0; i < taskGroups.Count(); i++) {
int temp = i; //This fixes the issue with i being shared
Thread thread = new Thread(() => RunThread(taskGroups[temp]));
threads.Add(thread);
thread.Start();
}
foreach (var thread in threads) {
thread.Join();
}
If you're using 3.5 then you can write your own CountdownEvent, if you're using 4.0 then you can use the built in CountdownEvent to do something like this:
CountdownEvent = new CountdownEvent(taskGroups.Count());
for (int i = 0; i < taskGroups.Count(); i++)
{
int item = i; // copy i locally
ThreadStart t = delegate
{
RunThread(taskGroups[item]);
latch.Signal();
};
new Thread(t).Start();
}
latch.Wait();
The latch.Wait() will cause your code to block until the threads have all finished. Furthermore, you might want to change the way you start your thread a bit:
CountdownEvent = new CountdownEvent(taskGroups.Count());
for (int i = 0; i < taskGroups.Count(); i++)
{
int item = i; // copy i locally
Thread t = new Thread(()=>
{
RunThread(taskGroups[item]);
latch.Signal();
});
t.IsBackground = true;
t.Start();
}
latch.Wait();
Note that I'm setting the thread to background: this your application from hanging when exit and not all threads have finished (i.e. prevents ghost or daemon threads).
You can use Thread.Join to make sure that each individual thread has finished running.
You can add public static integer field to the main thread, in each child thread increase it by one when it's completed then in the main thread wait (in a loop) until that variable is equal to the taskGroups.Count().
First of all consider switching to the new asynchronous pattern using Task.
Anyway if you want to wait for all your threads you can call Thread.Join:
var threads = new List<Thread>();
for (int i = 0; i < taskGroups.Count(); i++) {
ThreadStart t = delegate { RunThread(taskGroups[i]); };
var thread = new Thread(t);
threads.Add(thread);
thread.Start();
}
threads.ForEach(a => a.Join());
Remember that you can also pass a timeout parameter that will wait until the thread finishes only if it doesn't takes more than the time you passed in.
You can check the ThreadState property of each Thread object.

Categories

Resources