Threads - Simulation of execution time - c#

I have two secondary threads,that executes the method WriteX as described below:
static void Main(string[] args)
{
ThreadStart one = new ThreadStart(WriteX);
Thread startOne = new Thread(one);
ThreadStart two = new ThreadStart(WriteX);
Thread startTwo = new Thread(two);
startOne.Start();
startTwo.Start();
Console.ReadKey(true);
}
public static void WriteX()
{
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("Hello");
Thread.Sleep(1000);
}
}
( 1 ) How can i find the time taken (in milli seconds) by "startOne" and "startTwo" to complete its task?
( 2 ) I started the Thread (Start() ).Won't i need to stop the thread upon successful execution or will that be handled by the primary thread (Main() in this case) ?
(3) How can i print the message say , startOne is executing WriteX() method and startTwo is executing WriteX() method ?

In every serious logging framework, you can include the thread Id, or the thread name in the output message. If you just want to use the Console, you may have to manually append the current thread id/name to your message.
Like so:
public static void WriteX()
{
var sw = Stopwatch.StartNew();
for (int i = 1; i <= 3; i++)
{
Console.WriteLine("Hello");
Thread.Sleep(1000);
}
sw.Stop();
Console.WriteLine("{0} {1}",
Thread.CurrentThread.ManagedThreadId,
sw.Elapsed);
}
To name a thread, just use the Name property on the thread instance:
ThreadStart one = new ThreadStart(WriteX);
Thread startOne = new Thread(one);
startOne.Name = "StartOne";
//...
Console.WriteLine("{0} {1}", Thread.CurrentThread.Name, sw.Elapsed);
Also, when the method you pass as ThreadStart constructor argument finishes, the thread ends automatically. Use the Join method if you want to wait for a thread end in the main one.

Wrap WriteX() in something that saves the current time before and after (or simply do it at the begin and end of WriteX()) and print the difference at the end.
When the method passed to ThreadStart finishes, the thread terminates itself (and cleans itself up)
Again, wrap WriteX() in something that does the logging. I suggest to look at the source for ThreadStart to see how it's implemented and how you can extend/wrap it.
If you have no idea what I'm talking about, this article might help.

It depends on whether you want to get sum of execution times of two independent tasks or the biggest one. In first case you need to measure required time within WriteX. In the second case before startOne and stop measuring when both ar finished. Use Stopwatch in both cases.
Use Thread.Join to wait until both threads are finished.
Use parameterized start Thread.Start(object) and pass task name there.

Related

Join statement in multiple thread

I have a program that starts 2 threads and use Join.My understanding says that joins blocks the calling operation till it is finished executing .So,the below program should give 2 Million as answer since both the threads blocks till execution is completed but I am always getting the different value.This might be because first thread is completed but second thread is not run completely.
Can someone please explain the output.
Reference -Multithreading: When would I use a Join?
namespace ThreadSample
{
class Program
{
static int Total = 0;
public static void Main()
{
Thread thread1 = new Thread(Program.AddOneMillion);
Thread thread2 = new Thread(Program.AddOneMillion);
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("Total = " + Total);
Console.ReadLine();
}
public static void AddOneMillion()
{
for (int i = 1; i <= 1000000; i++)
{
Total++;
}
}
}
}
When you call start method of thread, it starts immediately. hence by the time u call join on the thread1, thread2 would also have started. As a result variable 'Total' will be accessed by both threads simultaneously. Hence you will not get correct result as one thread operation is overwriting the value of 'Total' value causing data lose.
public static void Main()
{
Thread thread1 = new Thread(Program.AddOneMillion);
Thread thread2 = new Thread(Program.AddOneMillion);
thread1.Start(); //starts immediately
thread2.Start();//starts immediately
thread1.Join(); //By the time this line executes, both threads have accessed the Total varaible causing data loss or corruption.
thread2.Join();
Console.WriteLine("Total = " + Total);
Console.ReadLine();
}
Inorder to correct results either u can lock the Total variable as follows
static object _l = new object();
public static void AddOneMillion()
{
for (int i = 0; i < 1000000; i++)
{
lock(_l)
ii++;
}
}
U can use Interlocked.Increment which atomically updates the variable.
Please refer the link posted by #Emanuel Vintilă in the comment for more insight.
public static void AddOneMillion()
{
for (int i = 0; i < 1000000; i++)
{
Interlocked.Increment(ref Total);
}
}
It's because the increment operation is not done atomically. That means that each thread may hold a copy of Total and increment it. To avoid that you can use a lock or Interlock.Increment that is specific to incrementing a variable.
Clarification:
thread 1: read copy of Total
thread 2: read copy of Total
thread 1: increment and store Total
thread 2: increment and store Total (overwriting previous value)
I leave you with all possible scenarios where things could go wrong.
I would suggest avoiding explicit threading when possible and use map reduce operations that are less error prone.
You need to read about multi-threading programming and functional programming constructs available in mainstream languages. Most languages have added libraries to leverage the multicore capabilities of modern CPUs.

Releasing all locked threads

I want to release all locked threads after one of them passes and complete the some task. Let me post some sample code about what I want to do. The important thing is they must pass all together after first thread completed his job. They(rest 99 threads) must be like that they have never locked not pass one by one.
Monitor.Enter(_lock);//imagine 100x threads hit this lock at same time.
//1 thread pass there
if (data == null)
{
data = GetData();
}
Monitor.Exit(_locker);//one more thread allow after this code.And they all come one by one in order.In these point I want to release them all together.
I have tried lots of class about threading like Monitor, Mutex, Semaphore, ReadWriteLock, ManaualResetEvent etc. but I didn't manage to do this, they all come one by one. Have you ever done this? Or Have you got ant idea about that? I don't wanna spent more time on it.
This might not be the most efficient way but it will work:
static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
static CancellationTokenSource cts = new CancellationTokenSource();
static void CriticalSection()
{
if(!cts.Token.IsCancellationRequested)
{
try
{
semaphore.Wait(cts.Token);
}
catch (OperationCanceledException ) { }
}
/*
Critical section here
*/
if(!cts.Token.IsCancellationRequested)
cts.Cancel();
}
the SemaphoreSlim will only let 1 thread run the "critical section". After the first thread is over with the section it will cancel the token. This will lead into an OperationCanceledException as described here. All the threads that were waiting will throw the exception that will be catched in the "try catch statement" and then execute the critical section. The first "if statement" is to check the state of the token to avoid the wait and throw pattern if it has been cancelled in the past.
The performance hit will be on the first time you have your threads "released" from the wait since they will all throw an exception. Later on, the only impact is going to be around the cancellation token check and the general maintainability of your code.
static SemaphoreSlim semaphore = new SemaphoreSlim(1);
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(LoadDataPart);
t.Name = (i + 1).ToString();
t.Start();
}
Console.Read();
}
static void LoadDataPart()
{
Console.WriteLine("Before Wait {0}", Thread.CurrentThread.Name);
semaphore.Wait();
Console.WriteLine("After Wait {0}", Thread.CurrentThread.Name);
Thread.Sleep(3000);
Console.WriteLine("Done {0}", Thread.CurrentThread.Name);
semaphore.Release(10);//this line must be changed,its allow too much thread coz its called 10 times!
}
I can manage what I want to do like this. In this code sample 10 threads hit wait. 9 of them waited other one keep going. When 1 thread done his job other 9 goes together not one by one. To check that I put thread sleep and all threads complated in 6 sec not in 30 secs. Now I can customize my code.

Safe Way to Limit Running Threads C#

I have a program I am writing that will run a variety of tasks. I have set up what I have called a "Task Queue" in which I will continually grab the next task to process (if there is one) and start a new thread to handle that task. However, I want to limit the amount of threads that can spawn at one time for apparent reasons. I created a variable to keep up with the max threads to spawn and one for the current thread count. I was thinking of using a lock to try and accurately keep up with the current thread count. Here is my general idea.
public class Program {
private static int mintThreadCount;
private static int mintMaxThreadCount = 10;
private static object mobjLock = new object();
static void Main(string[] args) {
mintThreadCount = 0;
int i = 100;
while(i > 0) {
StartNewThread();
i--;
}
Console.Read();
}
private static void StartNewThread() {
lock(mobjLock) {
if(mintThreadCount < mintMaxThreadCount) {
Thread newThread = new Thread(StartTask);
newThread.Start(mintThreadCount);
mintThreadCount++;
}
else {
Console.WriteLine("Max Thread Count Reached.");
}
}
}
private static void StartTask(object iCurrentThreadCount) {
int id = new Random().Next(0, 1000000);
Console.WriteLine("New Thread with id of: " + id.ToString() + " Started. Current Thread count: " + ((int)iCurrentThreadCount).ToString());
Thread.Sleep(new Random().Next(0, 3000));
lock(mobjLock) {
Console.WriteLine("Ending thread with id of: " + id.ToString() + " now.");
mintThreadCount--;
Console.WriteLine("Thread space release by id of: " + id.ToString() + " . Thread count now at: " + mintThreadCount);
}
}
}
Since I am locking in two places to access the same variable (increment when starting the new thread and decrement when ending it) is there a chance that the thread waiting on the lock to decrement could get hung up and never end? Thereby reaching max thread count and never being able to start another one? Any alternate suggestions to my method?
Easiest question first… :)
…is there a chance that the thread waiting on the lock to decrement could get hung up and never end?
No, not in the code you posted. None of the code holds a lock while waiting for the count to change, or anything like that. You only ever take the lock, then either modify the count or emit a message, and immediately release the lock. So no thread will hold the lock indefinitely, nor are there nested locks (which could lead to deadlock if done incorrectly).
Now, that said: from the code you posted and your question, it's not entirely clear what the intent here is. The code as written will indeed limit the number of threads created. But once that limit is reached (and it will do so quickly), the main loop will just spin, reporting "Max Thread Count Reached.".
Indeed, with a total loop count of 100, I think it's possible that the entire loop could finish before the first thread even gets to run, depending on what else is tying up CPU cores on your system. If some threads do get to run and it happens that some of them get very low durations to sleep, there's a chance that you might sneak in a few more threads later. But most of the iterations of the loop will see the thread count at the maximum, report the limit has been reached and continue with the next iteration of the loop.
You write in the comments (something you should really put in the question itself, if you think it's relevant) that "the main thread should never be blocked". Of course, the question there is, what is the main thread doing when not blocked? How will the main thread know if and when to try to schedule a new thread?
These are important details, if you want a really useful answer.
Note that you've been offered the suggestion of using a semaphore (specifically, SemaphoreSlim). This could be a good idea, but note that that class is typically used to coordinate multiple threads all competing for the same resource. For it to be useful, you'd actually have more than 10 threads, with the semaphore ensuring that only 10 get to run at a given time.
In your case, it seems to me that you are actually asking how to avoid creating the extra thread in the first place. I.e. you want the main loop to check the count and just not create a thread at all if the maximum count is reached. In that case, one possible solution might be to just use the Monitor class directly:
private static void StartNewThread() {
lock(mobjLock) {
while (mintThreadCount >= mintMaxThreadCount) {
Console.WriteLine("Max Thread Count Reached.");
Monitor.Wait(mobjLock);
}
Thread newThread = new Thread(StartTask);
newThread.Start(mintThreadCount);
mintThreadCount++;
}
}
}
The above will cause the StartNewThread() method to wait until the count is below the maximum, and then will always create a new thread.
Of course, each thread needs to signal that it's updated the count, so that the above loop can be released from the wait and check the count:
private readonly Random _rnd = new Random();
private static void StartTask(object iCurrentThreadCount) {
int id = _rnd.Next(0, 1000000);
Console.WriteLine("New Thread with id of: " + id.ToString() + " Started. Current Thread count: " + ((int)iCurrentThreadCount).ToString());
Thread.Sleep(_rnd.Next(0, 3000));
lock(mobjLock) {
Console.WriteLine("Ending thread with id of: " + id.ToString() + " now.");
mintThreadCount--;
Console.WriteLine("Thread space release by id of: " + id.ToString() + " . Thread count now at: " + mintThreadCount);
Monitor.Pulse(mobjLock);
}
}
The problem with the above is that it will block the main loop. Which if I understood correctly, you don't want.
(Note: you have a common-but-serious bug in your code, in that you create a new Random object each time you want a random number. To use the Random class correctly, you must create just one instance and reuse it as you want new random numbers. I've adjusted the code example above to fix that problem).
One of the other problems, both with the above, and with your original version, is that each new task is assigned a brand new thread. Threads are expensive to create and even to simply exist, which is why thread pools exist. Depending on what your actual scenario is, it's possible that you should just be using e.g. the Parallel, ParallelEnumerable, or Task to manage your tasks.
But if you really want to do this all explicitly, one option is to simply start up ten threads, and have them retrieve data to operate on from a BlockingCollection<T>. Since you start exactly ten threads, you know you'll never have more than that running. When there is enough work for all ten threads to be busy, they will be. Otherwise, the queue will be empty and some or all will be waiting for new data to show in the queue. Idle, but not using any CPU resources.
For example:
private BlockingCollection<int> _queue = new BlockingCollection<int>();
private static void StartThreads() {
for (int i = 0; i < mintMaxThreadCount; i++) {
new Thread(StartTask).Start();
}
}
private static void StartTask() {
// NOTE: a random number can't be a reliable "identification", as two or
// more threads could theoretically get the same "id".
int id = new Random().Next(0, 1000000);
Console.WriteLine("New Thread with id of: " + id.ToString() + " Started.");
foreach (int i in _queue) {
Thread.Sleep(i);
}
Thread.Sleep(new Random().Next(0, 3000));
}
You'd call StartThreads() just once somewhere, rather than calling your other StartNewThread() method multiple times. Presumably, before the while (true) loop you mentioned.
Then as the need to process some task, you just add data to the queue, e.g.:
_queue.Add(_rnd.Next(0, 3000));
When you want the threads to all exit (e.g. after your main loop exits, however that happens):
_queue.CompleteAdding();
That will cause each of the foreach loops in progress to end, letting each thread exit.
Of course, the T type parameter for BlockingCollection<T> can be anything. Presumably, it will be whatever in your case actually represents a "task". I used int, only because that was effectively your "task" in your example (i.e. the number of milliseconds the thread should sleep).
Then your main thread can just do whatever it normally does, calling the Add() method to dispatch new work to your consumer threads as needed.
Again, without more details I can't really comment on whether this approach would be better than using one of the built-in task-running mechanisms in .NET. But it should work well, given what you've explained so far.

How do Tasks in the Task Parallel Library affect ActivityID?

Before using the Task Parallel Library, I have often used CorrelationManager.ActivityId to keep track of tracing/error reporting with multiple threads.
ActivityId is stored in Thread Local Storage, so each thread get's its own copy. The idea is that when you fire up a thread (activity), you assign a new ActivityId. The ActivityId will be written to the logs with any other trace information, making it possible to single out the trace information for a single 'Activity'. This is really useful with WCF as the ActivityId can be carried over to the service component.
Here is an example of what I'm talking about:
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(new WaitCallback((o) =>
{
DoWork();
}));
}
static void DoWork()
{
try
{
Trace.CorrelationManager.ActivityId = Guid.NewGuid();
//The functions below contain tracing which logs the ActivityID.
CallFunction1();
CallFunction2();
CallFunction3();
}
catch (Exception ex)
{
Trace.Write(Trace.CorrelationManager.ActivityId + " " + ex.ToString());
}
}
Now, with the TPL, my understanding is that multiple Tasks share Threads. Does this mean that ActivityId is prone to being reinitialized mid-task (by another task)? Is there a new mechanism to deal with activity tracing?
I ran some experiments and it turns out the assumption in my question is incorrect - multiple tasks created with the TPL do not run on the same thread at the same time.
ThreadLocalStorage is safe to use with TPL in .NET 4.0, since a thread can only be used by one task at a time.
The assumption that tasks can share threads concurrently was based on an interview I heard about c# 5.0 on DotNetRocks (sorry, I can't remember which show it was) - so my question may (or may not) become relevant soon.
My experiment starts a number of tasks, and records how many tasks ran, how long they took, and how many threads were consumed. The code is below if anyone would like to repeat it.
class Program
{
static void Main(string[] args)
{
int totalThreads = 100;
TaskCreationOptions taskCreationOpt = TaskCreationOptions.None;
Task task = null;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task[] allTasks = new Task[totalThreads];
for (int i = 0; i < totalThreads; i++)
{
task = Task.Factory.StartNew(() =>
{
DoLongRunningWork();
}, taskCreationOpt);
allTasks[i] = task;
}
Task.WaitAll(allTasks);
stopwatch.Stop();
Console.WriteLine(String.Format("Completed {0} tasks in {1} milliseconds", totalThreads, stopwatch.ElapsedMilliseconds));
Console.WriteLine(String.Format("Used {0} threads", threadIds.Count));
Console.ReadKey();
}
private static List<int> threadIds = new List<int>();
private static object locker = new object();
private static void DoLongRunningWork()
{
lock (locker)
{
//Keep a record of the managed thread used.
if (!threadIds.Contains(Thread.CurrentThread.ManagedThreadId))
threadIds.Add(Thread.CurrentThread.ManagedThreadId);
}
Guid g1 = Guid.NewGuid();
Trace.CorrelationManager.ActivityId = g1;
Thread.Sleep(3000);
Guid g2 = Trace.CorrelationManager.ActivityId;
Debug.Assert(g1.Equals(g2));
}
}
The output (of course this will depend on the machine) was:
Completed 100 tasks in 23097 milliseconds
Used 23 threads
Changing taskCreationOpt to TaskCreationOptions.LongRunning gave different results:
Completed 100 tasks in 3458 milliseconds
Used 100 threads
Please forgive my posting this as an answer as it is not really answer to your question, however, it is related to your question since it deals with CorrelationManager behavior and threads/tasks/etc. I have been looking at using the CorrelationManager's LogicalOperationStack (and StartLogicalOperation/StopLogicalOperation methods) to provide additional context in multithreading scenarios.
I took your example and modified it slightly to add the ability to perform work in parallel using Parallel.For. Also, I use StartLogicalOperation/StopLogicalOperation to bracket (internally) DoLongRunningWork. Conceptually, DoLongRunningWork does something like this each time it is executed:
DoLongRunningWork
StartLogicalOperation
Thread.Sleep(3000)
StopLogicalOperation
I have found that if I add these logical operations to your code (more or less as is), all of the logical operatins remain in sync (always the expected number of operations on stack and the values of the operations on the stack are always as expected).
In some of my own testing I found that this was not always the case. The logical operation stack was getting "corrupted". The best explanation I could come up with is that the "merging" back of the CallContext information into the "parent" thread context when the "child" thread exits was causing the "old" child thread context information (logical operation) to be "inherited" by another sibling child thread.
The problem might also be related to the fact that Parallel.For apparently uses the main thread (at least in the example code, as written) as one of the "worker threads" (or whatever they should be called in the parallel domain). Whenever DoLongRunningWork is executed, a new logical operation is started (at the beginning) and stopped (at the end) (that is, pushed onto the LogicalOperationStack and popped back off of it). If the main thread already has a logical operation in effect and if DoLongRunningWork executes ON THE MAIN THREAD, then a new logical operation is started so the main thread's LogicalOperationStack now has TWO operations. Any subsequent executions of DoLongRunningWork (as long as this "iteration" of DoLongRunningWork is executing on the main thread) will (apparently) inherit the main thread's LogicalOperationStack (which now has two operations on it, rather than just the one expected operation).
It took me a long time to figure out why the behavior of the LogicalOperationStack was different in my example than in my modified version of your example. Finally I saw that in my code I had bracketed the entire program in a logical operation, whereas in my modified version of your test program I did not. The implication is that in my test program, each time my "work" was performed (analogous to DoLongRunningWork), there was already a logical operation in effect. In my modified version of your test program, I had not bracketed the entire program in a logical operation.
So, when I modified your test program to bracket the entire program in a logical operation AND if I am using Parallel.For, I ran into exactly the same problem.
Using the conceptual model above, this will run successfully:
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
While this will eventually assert due to an apparently out of sync LogicalOperationStack:
StartLogicalOperation
Parallel.For
DoLongRunningWork
StartLogicalOperation
Sleep(3000)
StopLogicalOperation
StopLogicalOperation
Here is my sample program. It is similar to yours in that it has a DoLongRunningWork method that manipulates the ActivityId as well as the LogicalOperationStack. I also have two flavors of kicking of DoLongRunningWork. One flavor uses Tasks one uses Parallel.For. Each flavor can also be executed such that the whole parallelized operation is enclosed in a logical operation or not. So, there are a total of 4 ways to execute the parallel operation. To try each one, simply uncomment the desired "Use..." method, recompile, and run. UseTasks, UseTasks(true), and UseParallelFor should all run to completion. UseParallelFor(true) will assert at some point because the LogicalOperationStack does not have the expected number of entries.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace CorrelationManagerParallelTest
{
class Program
{
static void Main(string[] args)
{
//UseParallelFor(true) will assert because LogicalOperationStack will not have expected
//number of entries, all others will run to completion.
UseTasks(); //Equivalent to original test program with only the parallelized
//operation bracketed in logical operation.
////UseTasks(true); //Bracket entire UseTasks method in logical operation
////UseParallelFor(); //Equivalent to original test program, but use Parallel.For
//rather than Tasks. Bracket only the parallelized
//operation in logical operation.
////UseParallelFor(true); //Bracket entire UseParallelFor method in logical operation
}
private static List<int> threadIds = new List<int>();
private static object locker = new object();
private static int mainThreadId = Thread.CurrentThread.ManagedThreadId;
private static int mainThreadUsedInDelegate = 0;
// baseCount is the expected number of entries in the LogicalOperationStack
// at the time that DoLongRunningWork starts. If the entire operation is bracketed
// externally by Start/StopLogicalOperation, then baseCount will be 1. Otherwise,
// it will be 0.
private static void DoLongRunningWork(int baseCount)
{
lock (locker)
{
//Keep a record of the managed thread used.
if (!threadIds.Contains(Thread.CurrentThread.ManagedThreadId))
threadIds.Add(Thread.CurrentThread.ManagedThreadId);
if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
{
mainThreadUsedInDelegate++;
}
}
Guid lo1 = Guid.NewGuid();
Trace.CorrelationManager.StartLogicalOperation(lo1);
Guid g1 = Guid.NewGuid();
Trace.CorrelationManager.ActivityId = g1;
Thread.Sleep(3000);
Guid g2 = Trace.CorrelationManager.ActivityId;
Debug.Assert(g1.Equals(g2));
//This assert, LogicalOperation.Count, will eventually fail if there is a logical operation
//in effect when the Parallel.For operation was started.
Debug.Assert(Trace.CorrelationManager.LogicalOperationStack.Count == baseCount + 1, string.Format("MainThread = {0}, Thread = {1}, Count = {2}, ExpectedCount = {3}", mainThreadId, Thread.CurrentThread.ManagedThreadId, Trace.CorrelationManager.LogicalOperationStack.Count, baseCount + 1));
Debug.Assert(Trace.CorrelationManager.LogicalOperationStack.Peek().Equals(lo1), string.Format("MainThread = {0}, Thread = {1}, Count = {2}, ExpectedCount = {3}", mainThreadId, Thread.CurrentThread.ManagedThreadId, Trace.CorrelationManager.LogicalOperationStack.Peek(), lo1));
Trace.CorrelationManager.StopLogicalOperation();
}
private static void UseTasks(bool encloseInLogicalOperation = false)
{
int totalThreads = 100;
TaskCreationOptions taskCreationOpt = TaskCreationOptions.None;
Task task = null;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StartLogicalOperation();
}
Task[] allTasks = new Task[totalThreads];
for (int i = 0; i < totalThreads; i++)
{
task = Task.Factory.StartNew(() =>
{
DoLongRunningWork(encloseInLogicalOperation ? 1 : 0);
}, taskCreationOpt);
allTasks[i] = task;
}
Task.WaitAll(allTasks);
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StopLogicalOperation();
}
stopwatch.Stop();
Console.WriteLine(String.Format("Completed {0} tasks in {1} milliseconds", totalThreads, stopwatch.ElapsedMilliseconds));
Console.WriteLine(String.Format("Used {0} threads", threadIds.Count));
Console.WriteLine(String.Format("Main thread used in delegate {0} times", mainThreadUsedInDelegate));
Console.ReadKey();
}
private static void UseParallelFor(bool encloseInLogicalOperation = false)
{
int totalThreads = 100;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StartLogicalOperation();
}
Parallel.For(0, totalThreads, i =>
{
DoLongRunningWork(encloseInLogicalOperation ? 1 : 0);
});
if (encloseInLogicalOperation)
{
Trace.CorrelationManager.StopLogicalOperation();
}
stopwatch.Stop();
Console.WriteLine(String.Format("Completed {0} tasks in {1} milliseconds", totalThreads, stopwatch.ElapsedMilliseconds));
Console.WriteLine(String.Format("Used {0} threads", threadIds.Count));
Console.WriteLine(String.Format("Main thread used in delegate {0} times", mainThreadUsedInDelegate));
Console.ReadKey();
}
}
}
This whole issue of if LogicalOperationStack can be used with Parallel.For (and/or other threading/Task constructs) or how it can be used probably merits its own question. Maybe I will post a question. In the meantime, I wonder if you have any thoughts on this (or, I wonder if you had considered using LogicalOperationStack since ActivityId appears to be safe).
[EDIT]
See my answer to this question for more information about using LogicalOperationStack and/or CallContext.LogicalSetData with some of the various Thread/ThreadPool/Task/Parallel contstructs.
See also my question here on SO about LogicalOperationStack and Parallel extensions:
Is CorrelationManager.LogicalOperationStack compatible with Parallel.For, Tasks, Threads, etc
Finally, see also my question here on Microsoft's Parallel Extensions forum:
http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/7c5c3051-133b-4814-9db0-fc0039b4f9d9
In my testing it looks like Trace.CorrelationManager.LogicalOperationStack can become corrupted when using Parallel.For or Parallel.Invoke IF you start a logical operation in the main thread and then start/stop logical operations in the delegate. In my tests (see either of the two links above) the LogicalOperationStack should always have exactly 2 entries when DoLongRunningWork is executing (if I start a logical operation in the main thread before kicking of DoLongRunningWork using various techniques). So, by "corrupted" I mean that the LogicalOperationStack will eventually have many more than 2 entries.
From what I can tell, this is probably because Parallel.For and Parallel.Invoke use the main thread as one of the "worker" threads to perform the DoLongRunningWork action.
Using a stack stored in CallContext.LogicalSetData to mimic the behavior of the LogicalOperationStack (similar to log4net's LogicalThreadContext.Stacks which is stored via CallContext.SetData) yields even worse results. If I am using such a stack to maintain context, it becomes corrupted (i.e. does not have the expected number of entries) in almost all of the scenarios where I have a "logical operation" in the main thread and a logical operation in each iteration/execution of the DoLongRunningWork delegate.

Please help. Creating threads and wait till finish [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# Spawn Multiple Threads for work then wait until all finished
I have two method calls that I want to call using two threads. Then I want them to wait till method executions get completed before continuing. My sample solution is something like below.
public static void Main()
{
Console.WriteLine("Main thread starting.");
String[] strThreads = new String[] { "one", "two" };
String ctemp = string.Empty;
foreach (String c in strThreads)
{
ctemp = c;
Thread thread = new Thread(delegate() { MethodCall(ctemp); });
thread.Start();
thread.Join();
}
Console.WriteLine("Main thread ending.");
Console.Read();
}
public static void MethodCalls(string number)
{
Console.WriteLine("Method call " + number);
}
Is this will do the job? Or is there another better way to do the same thing?
I'd look into running your method via ThreadPool.QueueUserWorkItem and then using WaitHandle.WaitAll to wait for all of them to complete.
This sequence of statements...:
Thread thread = new Thread(delegate() { MethodCall(ctemp); });
thread.Start();
thread.Join();
is equivalent to just calling the method directly -- since you're waiting for the new thread to finish right after starting it, there's no benefit from threading! You need to first start all threads in a loop (put them in an array list or some similar container), then join them in a separate loop, to get concurrent execution of the methods.
What you're doing ther eis creating a thread and then waiting to finish, one by one. You have, at any time, at most two thread running: the main and the one started.
What you want is to start all threads, then wait for all to complete:
public static void Main()
{
Console.WriteLine("Main thread starting.");
String[] strThreads = new String[] { "one", "two" };
int threadCount = strThreads.Length;
AutoResetEvent eventdone = new AutoResetEvent(false);
String ctemp = string.Empty;
foreach (String c in strThreads)
{
ctemp = c;
Thread thread = new Thread(delegate() {
try
{
MethodCall(ctemp);
}
finally
{
if (0 == Interlocked.Decrement(ref threadCount)
{
eventDone.Set();
}
}
});
thread.Start();
}
eventDone.WaitOne();
Console.WriteLine("Main thread ending.");
Console.Read();
}
public static void MethodCalls(string number)
{
Console.WriteLine("Method call " + number);
}
If you intended for your two threads to execute one after the other, then yes, the above code will suffice (though my C# syntax knowledge is a little fuzzy off the top of my head so I can't say if the above compiles nicely or not), but why use threads if you want ordered, synchronous execution?
If instead what you want is for the two method calls to execute in parallel, you need to take the thread.Join(); out of the for-loop (you'll need to hang on to the thread objects, likely in an array.)
Take a look at BackgroundWorker Component; I beleive it works with Windows Forms, WPF and Silverlight, basically somewhere UI is involved

Categories