Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more: , +
I am currently learning about multithreading. I have a book (Exam 70-536 self-paced training kit) which gives an example about multi-threading.
So I have tried this (taken from the book). The code is as follows:

VB
Imports System.Threading

Public Class FastMemFile
    Private _file As String = "Hello, World!"
    Private _rwl As New ReaderWriterLock

    Public Sub ReadFile()
        _rwl.AcquireReaderLock(10000)
        For i As Integer = 1 To 3
            Console.WriteLine(_file)
            Thread.Sleep(1000)
        Next
        _rwl.ReleaseReaderLock()
    End Sub

    Public Sub WriteFile()
        _rwl.AcquireWriterLock(10000)
        _file += " It's a nice day!"
        _rwl.ReleaseWriterLock()
    End Sub

End Class

Public Class SlowMemFile
    Private _file As String = "Hello, World!"

    Public Sub ReadFile()
        SyncLock Me
            For i As Integer = 1 To 3
                Console.WriteLine(_file)
                Thread.Sleep(1000)
            Next
        End SyncLock
    End Sub

    Public Sub WriteFile()
        SyncLock Me
            _file += " It's a nice day!"
        End SyncLock
    End Sub

End Class


As you see the classes do exactly the same, except that the FastMemFile uses a ReaderWriterLock and the SlowMemFile uses SyncLock. The calling code looks like this:

VB
Imports System.Threading

Module Module1

    Sub Main()
        Dim m As New SlowMemFile ' / FastMemFile

        Dim t1 As New Thread(New ThreadStart(AddressOf m.ReadFile))
        Dim t2 As New Thread(New ThreadStart(AddressOf m.WriteFile))
        Dim t3 As New Thread(New ThreadStart(AddressOf m.ReadFile))
        Dim t4 As New Thread(New ThreadStart(AddressOf m.ReadFile))

        t1.Start()
        t2.Start()
        t3.Start()
        t4.Start()
    End Sub

End Module

The FastMemFile is indeed much faster than the SlowMemFile. However the results I get seems to be completely random (for both classes). Sometimes I get "Hello, World!" 9 times, sometimes I get "Hello, World! It's a nice day" 9 times, and sometimes I get "Hello, World!" 3 times and "It's a nice day!" 6 times and yet other times it's the other way around...
Does this have anything to do with me having an ultra-fast Intel Core i7?
And if this is so then how can I make sure my code does actually execute in the right order, but on seperate threads? I want to make sure the code executes correctly no matter the processor speed.
Some code examples are appreciated, but some good articles that address the problem are actually more welcome.
Posted
Updated 15-Apr-11 5:46am
v2

Hi,
Synchronization locks just to make sure only one thread access the resource at a time. While reader and writer locks do the same , but offer little flexibility to read while it make sure no writing happens while others reading. The order of the threads executes simply random. It is not controllable from code.
 
Share this answer
 
Comments
Sander Rossel 15-Apr-11 12:45pm    
How nice of the book to not mention this... But basically this means I should never create multiple threads for methods that should be executed in a fixed order?
Albin Abel 15-Apr-11 13:42pm    
The very first question is if the methods has to be executed one by one then why we need multiple threads?
Sander Rossel 15-Apr-11 19:33pm    
Well, it is obvious such long-running tasks as Console.Writeline(_file) need to be executed on a background thread ;)
Of course that is only an example, and a not so good one too, because I would have expected "Hello, World!" 3 times and "It's a nice day!" 6 times. Thanks for the answer. It cleared a lot up :)
Albin Abel 16-Apr-11 0:27am    
Right. Long running process can be delegated to background threads. But you can't predict the order that first thread finish the job first. If you make it order it will be mess enough. Let us take your example. Say you have crated 5 threads to read a same resource and another 5 threads to do a simple arithmatic. If there is a order then the five threads which do a simple task has to wait a long time. That is just ugly. So this gate allows every one get a chance some time. If there is a order then one thread perform an infinite loop will block everybody else. But there are priorities. Even in the peak traffic the fire engine get a way to go. Like that high priority threads get high chance of entering in to CPU. However you controlling the time a single thread can spend on the resource using the reader and writer lock. As you are learning I am posting an another example code which explains it.
Here is an example code.

C#
public class ThreadTest
{
    private string _file="Hello World";
    private ReaderWriterLock _rw1=new ReaderWriterLock();
    public void ReadFile(object obj)
    {
        _rw1.AcquireReaderLock(1000);
        for(int i=0;i<10;i++)
        {
            if ((int)obj == 1)
            {
                Thread.Sleep(10000);
            }
            else
            {
                Thread.Sleep(1000);
            }
        }
           System.Windows.Forms.MessageBox.Show(_file+" is accessed by "+obj.ToString());
        _rw1.ReleaseReaderLock();
    }
}



Then call this using
C#
ThreadTest t = new ThreadTest();
Thread th1=new Thread(new ParameterizedThreadStart(t.ReadFile));
Thread th2 = new Thread(new ParameterizedThreadStart(t.ReadFile));

th1.Start(1);
th2.Start(2);


Here the th1 is called first. Do you expect th2 has to wait till th1 finishes the job? as the order it called.
 
Share this answer
 
Comments
Sander Rossel 16-Apr-11 6:06am    
I think that if the first thread would have completed within the second there would be no problem, since the method gets locked for a second (but how would you ever know? You won't). However, after a second the lock is unlocked and thread two starts to execute it too. It finishes earlier than the first thread. This would become a mess if the second thread would do something like _file += " test ", because thread one would now show a messagebox with a text that it did not intent to show. Even worse, when saying for(int i=0;i<2;i++), have thread one wait 1000ms in the loop too and have thread two do += " test " you sometimes get "hello world test was accessed by 1" and sometimes you get "test test". Which actually means that sometimes thread two may 'catch up' with thread one, which makes the outcome even more unpredictable...
esmailian 16-Apr-11 8:24am    
This is( th1.Start(1);th2.Start(2); ) how deffrence with .join
When use .join stay to finish thread last go to next line
th1.start();
th1.join();
th2.start();

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900