[平行處理 - 2] Parallel.For + Lock

  • 29730
  • 0
  • C#
  • 2018-04-09

Parallel.For很明顯跟上一篇Parallel.Foreach是差不多的東西

所以我們再加上 Lock 來讓情況變有趣些

 

假設我戶頭共有100塊 每次領錢都領10塊

領到戶頭歸零就不能再領了

單執行緒的情況大家都知道該怎麼寫

但今天如果是平行處理 一切同時發生 那我怎控制程式不出錯呢?

 

由此可知

1. 單執行緒肯定沒問題

2. 平行處理我無法預估誰會先領錢、或也許是一起在領錢,故我們得對領錢這個動作上鎖

=> 一次只能有一個人在領錢

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication2
{
    /// <summary>
    /// 示範 Parallel.For + Lock
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 1; i <= 5; i++)
            {
                Console.WriteLine("【第" + i.ToString() + "回合】共有 100 塊, 每次領 10 塊");
                Single();
                Multi();
                Console.WriteLine();
            }

            Console.Read();
        }

        private static void Single()
        {
            ATM myDb = new ATM();

            Console.WriteLine("單執行緒");
            for (int i = 1; i < 15; i++)
            {
                Console.WriteLine("序號" + i.ToString("00") + ":" + myDb.Withdraw());
            }

            Console.WriteLine();
        }

        private static void Multi()
        {
            ATM myATM = new ATM();

            Console.WriteLine("平行處理");
            Parallel.For(1, 15, i =>
            {
                Thread.Sleep(300);
                Console.WriteLine("序號" + i.ToString("00") + ":" + myATM.Withdraw());
            });

            Console.WriteLine();
        }
    }

    class ATM
    {
        private Object _lock = new Object();
        int money = 100;

        public string Withdraw()
        {
            if (NoMoney()) return "錢不夠";

            //表示會有很多人在這等待進入lock區 (但同時只能一人進入)
            lock (_lock)
            {
                //也許他通過驗證'錢不夠' 已經是一小時前了 
                //但在門口排隊一小時才輪到他進來 
                //所以你如何確定現在餘額還夠呢?
                if (NoMoney()) return "錢不夠"; 

                money -= 10;
                return "還剩" + money;
            }
        }

        private bool NoMoney()
        {
            return (money - 10) < 0;
        }
    }
}

 

提醒大家一個重點

我們只能確認進入Lock以後一定是一次一個

其他地方發生過的事都不算數

故你在其他地方做過什麼 你得再Lock區內再做一次

如同註解寫的

//也許他通過驗證'錢不夠' 已經是一小時前了 
//但在門口排隊一小時才輪到他進來 
//所以你如何確定現在餘額還夠呢?