What is condition synchronization?

2019-02-10 09:45发布

问题:

Could someone explain condition synchronization to me?

An example (preferably in C#) would be greatly appreciated also.

回答1:

It sounds like your professor is talking about threading. Threading enables computer programs to do more than one thing at a time. The act of starting a new thread while one is already running is called "spinning up a thread" by computer programmers.

Threads can share the same memory space. Condition Synchronization (or merely synchronization) is any mechanism that protects areas of memory from being modified by two different threads at the same time.

Let's say you are out doing shopping, and the wife is at home paying the bills. This is a naive example, and it doesn't really work this way in real life, but it will serve as a simple illustration.

Your wife is paying a bill online. At the same time, you are swiping your credit card at the grocery store. Both acts involve moving money out of your checking account. To simulate this activity, we write the following code:

public class MyBanking
{
    static double myAccountBalance;
    //
    public void DebitAccount(double debitAmount)
    {
        Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString());
        Console.Writeline("Your Debit is:       " + debitAmount.ToString());
        myAccountBalance = myAccountBalance - amount;
        Console.Writeline("Your New Balance is: " + myAccountBalance.ToString());
    }
}

Hypothetically, your wife is running one instance ("copy") of this class on one thread, you are running an instance on another thread. The myAccountBalance variable is declared static to allow it to be shared between both running instances (you and your wife have only one checking account).

You make your debit by calling the code like this:

MyBanking bankingObject = new MyBanking();
bankingObject.DebitAccount(100);

Your wife makes her debit at the same time:

MyBanking bankingObject = new MyBanking();
bankingObject.DebitAccount(50);

What happens if your thread gets interrupted by your wife's thread after your old balance is printed on the screen, but before the new balance is printed? Your wife's thread debits the account and returns control back to your thread. Your wife sees this on the screen:

Your Old Balance is: 2000
Your Debit is:       50
Your New Balance Is: 1950

When the computer prints the new balance on your screen, it will be wrong, because your wife's debit will have been counted also. You will see something like this:

Your Old Balance is: 2000
Your Debit is:       100
Your New Balance Is: 1850

To fix this, we surround our method code with a lock statement. The lock statement causes all other threads to wait for our instance to finish. The new code looks like this:

public class MyBanking
{
    static double myAccountBalance;
    //
    public void DebitAccount(double debitAmount)
    {
        lock (this)
        {
            Console.Writeline("Your Old Balance is: " + myAccountBalance.ToString());
            Console.Writeline("Your Debit is:       " + debitAmount.ToString());
            myAccountBalance = myAccountBalance - amount;
            Console.Writeline("Your New Balance is: " + myAccountBalance.ToString());
        }
    }
}

Your wife's thread will now wait for your code within the lock statement to finish executing, before your wife's code begins executing. Your new balance will now be correct, because there is no longer the possibility of your wife's thread changing the balance while you complete YOUR transaction. On your screen, you will now see this:

Your Old Balance is: 2000
Your Debit is:       100
Your New Balance Is: 1900

Your wife will see this:

Your Old Balance is: 1900
Your Debit is:       50
Your New Balance Is: 1850

This is synchronization.



回答2:

Basically it's a design pattern for threads that need

a) synchronize access to a resource

b) sometimes wait for other threads until a certain conditions is met

You ask this in a C# context, .NET provides support for this with Monitor.Wait and Monitor.Pulse (and with wrappers around various Win32 objects like WaitEventhandle).

Here is a nice queue example on SO.

The main technical details look like:

lock(buffer)  // is Monitor.Enter(buffer) ... finally Monitor.Leave(buffer)
{
   while (buffer.Count < 1)
   {
      Monitor.Wait(buffer); 
   }
   ...
}

Notice how there is a Wait-while-locked in there. It looks like a deadlock but Wait will release the lock while it is waiting. The code inside the lock() { } still has exclusive access to buffer when it runs.

And then another thread has to signal when it puts something into the buffer:

Monitor.Pulse(buffer);


回答3:

The code above is almost correct but is actually wrong. By using lock(this), you will only lock your instance of the MyBanking class, but your wife will lock hers. To lock access to the shared variable you can either lock the type (i.e. lock(typeof(MyBanking))) or you can introduce a new shared variable and lock that (you can't lock an int so typically people create an object as follows.

class MyBanking
{
    static object lockObj = new object();
    static double myAccountBalance;
    public void DebitAccount(double debitAmount)
    {
        lock (lockObj)


回答4:

Synchronisation has been clearly explained already. However, condition synchronisation specifically dictates that a process/thread executes only after some condition is met. Typically, the condition will be that some other process/thread has already executed.

In the given example of debiting an account and viewing the balance. If the viewing of your balance was a separate synchronized method and we wanted to view the balance only after your account had been debited, then this would require condition synchronisation.

Condition synchronisation is very well described by the producer-consumer problem.