Hi,

I have done a test using the lock(lockobject), which will be an interesting question.

I have created 2 background threads, that I start simultaniously. Threads uses a while(true) loop to produce the test.

If we uncomment and use the lock(lockobject) in the code. None of the loops will write values to any file. However if we doesn´t use the lock(lockobject) in the code. Values will be written to the file.

Tests goes for 2 scenarios(String or bool)
if (stringTest != "Test1" && stringTest != "Test2")
if (boolTest != true && boolTest != false)

When values are written to file(when we doesn´t use the lock(lockobject). Any of those will be written to file:
* "Test1"
* "Test2"
* "True"
* "False"

My question is what exactly is happening. How can values be written to file when not using the lock(lockobject).

Question
if (stringTest != "Test1" && stringTest != "Test2") ----> "Test1" or "Test2" is written to file anyway?
if (boolTest != true && boolTest != false) ----> "True" or "False" is written to file anyway?

        bool hasStarted = false;
        private void button1_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
            if (hasStarted == false)
            {
                Thread thread1 = new Thread(backgroundthread1); thread1.Start();
                Thread thread2 = new Thread(backgroundthread2); thread2.Start();
                hasStarted = true;
            }
        }

        object lockObject = new object();
        bool boolTest = false;
        String stringTest = "";

        void backgroundthread1()
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
            while (true)
            {
                //lock (lockObject)
                //{
                    boolTest = false;
                    stringTest = "Test1";

                    //if (stringTest != "Test1" && stringTest != "Test2")
                    if (boolTest != true && boolTest != false)
                    {
                        FileStream stream = new FileStream("C:/Test1.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                        StreamWriter writer = new StreamWriter(stream);
                        writer.WriteLine(boolTest + "," + stringTest);
                        writer.Close(); stream.Close();
                    }
                //}
            }
        }
        void backgroundthread2()
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
            while (true)
            {
                //lock (lockObject)
                //{
                    boolTest = true;
                    stringTest = "Test2";

                    //if (stringTest != "Test1" && stringTest != "Test2")
                    if (boolTest != true && boolTest != false)
                    {
                        FileStream stream = new FileStream("C:/Test2.txt", FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
                        StreamWriter writer = new StreamWriter(stream);
                        writer.WriteLine(boolTest + "," + stringTest);
                        writer.Close(); stream.Close();
                    }
                //}
            }
        }

Recommended Answers

All 4 Replies

Your if statements mean that no code will ever execute.

if(boolTest != true && boolTest != false) <-- This means "boolTest must be false AND boolTest must true" this is an impossible condition as they are mutually exclusive.

The same applies with your stringTest object the only difference being that strings can have a higher range of values so technically the argument is valid, just not in your case.

You say that it wrote to file? With the code you have there it is incredibly unlikely.

The only way it could possibly work is if the threads were spinning that fast, when your if statement checks the first condition (is false) it evaluates to true, the second thread updates the boolean to true before the first thread checks the second condition. As the second condition is now also true, the code will execute. This shouldn't happen all that often though, I would expect the output to be small over a large number of iterations.

The reason it wasn't working with the lock is because the second thead wouldn't be able to spin, so your boolean wouldn't update from the initial value you assign to it in the loop. This would cause the if statement to ultimately return false every time, guaranteed.

>> You say that it wrote to file? With the code you have there it is incredibly unlikely.

Yes it does write to file which also makes me wonder about the importance of the lock object.

Most probably it has to be like you describe it to. It is the only possibility I can find also that the bool changes before checking the second condition.

With this answer as reference for my initial questions that I wonder about, since there is hundreds of variables to perheps use lock object on:
>> The same applies with your stringTest object the only difference being that strings can have a higher range of values so technically the argument is valid, just not in your case.

And with those different variables:
int a = 1;
bool b = false;
long c = 123;

double d = 12.234;
String e = "Test1";

Question 1:
If two threads that Does Not use a lock object tries to read and write to an int,bool or long at the exact same time. Will this be any problem since those type of variables only can take a new (int) number or true/false?
(Reason is if that is the case, I wouldn´t need to use lock objects on those type of variables since it doesn´t matter if I lock them or not. However I still wonder if something else can go wrong if read/write to the same variable at exact same time, like corrupt memory etc?)

Question 2:
If two threads that Does Not use a lock object tries to read and write to a double or a String at the exact same time. Could this be a problem where for example the decimals can get lost like:
12.23 and not 12.234, therefore doesn´t be declared properly because of read/write at the exact same time?
Same would go for the String, like: "Tes" and not "Test1"?

In the worst case you'd generally end up with nonesense.

Init -> int myInt = 0;
Thread 1 -> myInt = 5;
Thread 2 -> myInt = 7;
Thread 1 -> if(myInt == 5) { /* Not called */ }
Thread 2 -> if(myInt == 7) { myInt = 9; }
Thread 1 -> myInt = 4;
Thread 2 -> return myInt; // returns 4, expected 9

Hence thread synchronisation is important.

Where fixed length objects are concerned you shouldn't end up with half of one number and half of another but it is possible.

Thread 1 -> Writing number 
Thread 1 > Write Byte 1 + 2 (0x00, 0x12)
Thread 2 > Write Byte 1 + 2 (0x10, 0xAA)
Thread 2 > Write Byte 3 + 4 (0x27, 0x01)
Thread 1 > Write Byte 3 + 4 (0x11, 0x37)

Result: 0x10AA1137 = 279580983
Thread 1 Expected = 0x00121137 -> 1184055
Thread 2 Expected = 0x10AA2701 -> 279586561

This is a very simplified case, but it could happen.

Using locks is very important where you are sharing memory (subject: thread synchronisation), however, if the two threads can run completely parallel without sharing memory, there is no need to lock them.

public class ThreadClass
{
    int myInt = 5;
    object padLock = new object();

    void SharedThreadedMethod()
    {
        // Lock is required, using shared memory
        lock(padLock)
        {
            if(myInt == 5)
            {
                //Stuff
            }
        }
    }
}

public class AnotherThreadClass
{
    void PrivateThreadedMethod(int myInt)
    {
        // No need to lock, no shared memory used.
        if(myInt == 5)
        {
            // Stuff
        }
    }
}

If in doubt, lock. It's perfectly viable to try and lock as little as possible. But as soon as you need to hit shared memory (for either read or write) for a period of time, where the state of the values matter, you must lock to avoid synchronisation issues.

In the interest of transparency and honesty, I should inform you that there is a keyword called volatile. This will ensure that the current thread finishes a complete read or write on the variable before another thread is allowed to proceed to access that variable.
Personally speaking, I would avoid the use of volatile, unless you're locking the entire thread specifically for the purpose of updating this variable. Additionally, hitting a volatile variable a lot will be more of a performance hit that acquiring a lock.

Example;

// Use volatile for this....

public volatile bool PerformUpdate = false;
object padLock = new object();
// Good
public void ThreadedMethod()
{
    if(PerformUpdate)
        // Do something that doesn't need to be synchronised
}

// Bad
public void AnotherMethod()
{
    // Unnecessary lock, will hold up application for no reason while the if statement logic completes
    lock(padLock)
    {
        if(PerformUpdate)
            // Do something that doesn't need to be synchronised
    }
}

...Somewhere else...

// Good
public void SetUpdate()
{
    PerformUpdate = true;
}

// Bad
public void SetUpdateSafe()
{
    // Unnecessary lock, waste of processor time
    lock(padLock)
    {
        PerformUpdate = true;
    }
}

Ketsuekiame,

Thanks alot for your explanation. I am going through all possible variables and put locks where it will be nessecary!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.