Trying to understand multithreading in C #

I'm trying to understand the basics of multithreading, so I created a small program that raised a few questions, and I will be grateful for any help :)

Here is a small program:

class Program { public static int count; public static int max; static void Main(string[] args) { int t = 0; DateTime Result; Console.WriteLine("Enter Max Number : "); max = int.Parse(Console.ReadLine()); Console.WriteLine("Enter Thread Number : "); t = int.Parse(Console.ReadLine()); count = 0; Result = DateTime.Now; List<Thread> MyThreads = new List<Thread>(); for (int i = 1; i < 31; i++) { Thread Temp = new Thread(print); Temp.Name = i.ToString(); MyThreads.Add(Temp); } foreach (Thread th in MyThreads) th.Start(); while (count < max) { } Console.WriteLine("Finish , Took : " + (DateTime.Now - Result).ToString() + " With : " + t + " Threads."); Console.ReadLine(); } public static void print() { while (count < max) { Console.WriteLine(Thread.CurrentThread.Name + " - " + count.ToString()); count++; } } } 

I checked this with some test runs:

I made a maximum number of 100, and it seems that the fastest runtime is 2 threads, which are 80% faster than time with 10 threads.

Questions:

1) Topics 4-10 are not printed even once, how can this be?

2) Shouldn't there be more threads?

I made a maximum number of 10,000 and turned off printing.

With this configuration, 5 threads seem to be the fastest.

Why is there a change from the first check?

And also in this configuration (with printing) all streams print several times. Why is this different from the first run, where only a few streams are printed?

Is there a way for all threads to print one after another? In line or something like that?

Many thanks for your help:)

+4
source share
3 answers

Your code is, of course, the first step into the world of threading, and you just experienced the first (of many) headaches!

To begin with, static can allow you to exchange a variable between threads, but that does not make it a safe thread. This means that your expression count < max and count++ not guaranteed to be a relevant or effective protector between threads. Look at the output of your program when max only 10 (t is set to 4, on my 8-processor workstation):

 T0 - 0 T0 - 1 T0 - 2 T0 - 3 T1 - 0 // wait T1 got count = 0 too! T2 - 1 // and T2 got count = 1 too! T2 - 6 T2 - 7 T2 - 8 T2 - 9 T0 - 4 T3 - 1 // and T3 got count = 1 too! T1 - 5 

To your question about each print stream, one after another, I assume that you are trying to coordinate access to count . You can accomplish this with synchronization primitives (such as the lock statement in C #). Here is a naive modification of your code that will only provide max increments:

 static object countLock = new object(); public static void printWithLock() { // loop forever while(true) { // protect access to count using a static object // now only 1 thread can use 'count' at a time lock (countLock) { if (count >= max) return; Console.WriteLine(Thread.CurrentThread.Name + " - " + count.ToString()); count++; } } } 

This simple modification makes your program logically correct, but also slow. A new problem now appears in the sample: block conflict. Each thread now vies for access to countLock . We made our program safe, but without any benefits of parallelism!

Threading and parallelism are not very easy to get right, but, fortunately, the latest versions of .Net come with Task Parallel Library (TPL) and Parallel LINQ (PLINQ) .

The beauty of the library is how easy it would be to convert your current code:

 var sw = new Stopwatch(); sw.Start(); Enumerable.Range(0, max) .AsParallel() .ForAll(number => Console.WriteLine("T{0}: {1}", Thread.CurrentThread.ManagedThreadId, number)); Console.WriteLine("{0} ms elapsed", sw.ElapsedMilliseconds); // Sample output from max = 10 // // T9: 3 // T9: 4 // T9: 5 // T9: 6 // T9: 7 // T9: 8 // T9: 9 // T8: 1 // T7: 2 // T1: 0 // 30 ms elapsed 

The above result is an interesting illustration of why threads produce "unexpected results" for new users. When threads execute in parallel, they can fill in pieces of code at different points in time, or one thread may be faster than another. You never know with threads!

+7
source

Your print function is far from streaming security, so 4-10 does not print. All threads have the same max and count variables.

The reason why more threads are slowing you down is likely to change state every time the processor changes focus between each thread.

In addition, when creating a large number of threads, the system must allocate new ones. Most of the time it’s now advisable to use Tasks instead, since they are pulled from a system-controlled thread pool. And therefore, it is not necessary to highlight. Creating a separate new thread is quite expensive.

Look here one way or another: http://msdn.microsoft.com/en-us/library/aa645740(VS.71).aspx

0
source

Look carefully:

  t = int.Parse(Console.ReadLine()); count = 0; Result = DateTime.Now; List<Thread> MyThreads = new List<Thread>(); for (int i = 1; i < 31; i++) { Thread Temp = new Thread(print); Temp.Name = i.ToString(); MyThreads.Add(Temp); } 

I think you missed the variable t (i <31).

Before writing code, you should read many books on parallel and multi-threaded programming, because a programming language is just a tool. Good luck

0
source

All Articles