伊莉討論區

標題: C#中 lock的使用? [打印本頁]

作者: ggnnyy    時間: 2017-10-12 10:15 AM     標題: C#中 lock的使用?

本帖最後由 ggnnyy 於 2017-10-12 10:25 AM 編輯

各位大大好:
最近在研究訂單系統的取號機制,在多人使用的環境下訂單編號能夠不被重複取用...
上網有搜尋到許多方法,但有人提到用如下方法,我查了一下lock的鎖定好像是針對程式碼區塊的鎖定,
所以訂單系統如果是網站型態的應該是可以鎖定,但是如果是winform的型態呢?  這樣lock能達到鎖定不讓多個使用者存取到一樣的單號嗎?
  1. private void LockInsert(object i)
  2. {
  3.         lock (thisLock)
  4.         {
  5.             using (SqlConnection myConnection = new SqlConnection(SqlDataSource1.ConnectionString))
  6.             {
  7.                 SqlCommand myCommand = new SqlCommand();
  8.                 myCommand.Connection = myConnection;
  9.                 myCommand.CommandText = "Insert Product (ProNo,ProName) values (@ProNo,@ProName)";
  10.                 myCommand.Parameters.AddWithValue("@ProNo", GetProductSerialNumber());
  11.                 myCommand.Parameters.AddWithValue("@ProName", "Product_" + i);
  12.                 myConnection.Open();
  13.                 myCommand.ExecuteNonQuery();
  14.             }
  15.         }
  16. }
複製代碼

作者: sam30525sam    時間: 2017-10-12 10:20 PM

本帖最後由 sam30525sam 於 2017-10-12 10:21 PM 編輯

lock不管你是 asp.net mvc 或 asp.net web api 或 webform都可以使用,這樣講好了,
不管你是應用程式還是網頁,其實核心都一樣,
但是要注意的點差蠻多就是了。

依照你的程式碼的話,你這個lock永遠都沒有用,
因為網頁每一次request近來,都會產生一個新的instance,
而且你又寫lock(this),這種最耗效能的東西,
整體看起來有點悲劇。

如果你要寫lock,我建議你參考以下看看
1. 要注意,所謂的lock就是「場上只有一個旗子,誰拿到,誰就可以做動作」
所以回過頭看你的程式碼,你就會發現instance會產生很多「同名稱,但不一樣的旗子」,
那如何才可以產生只有一個旗子呢?
那你就用static就好了。

2. lock是鎖什麼,就是鎖記憶體
看到一推新手常常寫lock(this),這代表是說,我要lock這整個class的instance,
這樣子就像是,
「我只是要拿一杯水,但是我要求全公司的人都不能動,我拿了水之後,你們才可以繼續」
但其他公司的人也許只是要列印文件,為什麼你拿水,明明沒關係,卻還要等你做完?
建議你根據該相對應的行為,建立相對應的「鎖」就好。

請參考以下範例
  1.     public static class LockExample
  2.     {
  3.         /// <summary>會員列表</summary>
  4.         private static List<string> _MemberList;

  5.         /// <summary>會員列表鎖</summary>
  6.         private static object _MemberListLocker;


  7.         /// <summary>歌曲列表</summary>
  8.         private static List<string> _SongList;

  9.         /// <summary>歌曲列表鎖</summary>
  10.         private static object _SongListLocker;


  11.         static LockExample()
  12.         {
  13.             LockExample._MemberList = new List<string>();
  14.             LockExample._MemberListLocker = new object();

  15.             LockExample._SongList = new List<string>();
  16.             LockExample._SongListLocker = new object();
  17.         }

  18.         public static string GetMember(int index)
  19.         {
  20.             lock (LockExample._MemberListLocker)
  21.             {
  22.                 return LockExample._MemberList[index];
  23.             }
  24.         }

  25.         public static void AddMember(string newMember)
  26.         {
  27.             lock (LockExample._MemberListLocker)
  28.             {
  29.                 LockExample._MemberList.Add(newMember);
  30.             }
  31.         }

  32.         public static string GetSong(int index)
  33.         {
  34.             lock (LockExample._SongListLocker)
  35.             {
  36.                 return LockExample._SongList[index];
  37.             }
  38.         }

  39.         public static void AddSong(string newSong)
  40.         {
  41.             lock (LockExample._SongListLocker)
  42.             {
  43.                 LockExample._SongList.Add(newSong);
  44.             }
  45.         }

  46.     }
複製代碼

作者: ggnnyy    時間: 2017-10-12 11:39 PM

感謝SAM大~~~~~
可否在請問,如果是winform的形式(不是webform喔)
為什麼這種方式也能鎖定?
既然是鎖定程式碼區塊,winform每個用戶端不是都是獨立的個體嗎?
作者: sam30525sam    時間: 2017-10-14 12:32 AM

ggnnyy 發表於 2017-10-12 11:39 PM
感謝SAM大~~~~~
可否在請問,如果是winform的形式(不是webform喔)
為什麼這種方式也能鎖定?

我的解法,winform/網頁程式都可以,

至於你說的winform每個用戶端都是獨立的個體,
這個你要定義你的client side是什麼,
我們通常定義client side就是一個應用程式,一個process。

但這個跟我所講的沒關係,
我所講的是class在實體化的時候,所配發的記憶體,
舉的例子來講,假設程式碼如下
  1. public class Dog
  2. {
  3.     public static int Hair { get; set; }
  4.     public int Size { get; set; }
  5. }
複製代碼
  1. Dog emily = new Dog();
  2. Dog shary = new Dog();
複製代碼
emily的Size跟shary的Size是不同份記憶體,
所以你lock Size是沒用的。

但是emily的Hair跟shary的Hair是同一份記憶體,
你lock Hair就有用。

詳細的請你自己去看static 與instance的差異在哪裡

作者: Jeepluo    時間: 2017-10-18 03:02 PM

如果只是要取訂單號碼,使用 Record Lock的方式並非是個好的方式,甚至是一個很不好的方法,取單號的方式有很多,就看你的單號顯示的重要性。
例如說:
如果只是要有一個單號做區分,可以在存檔時利用 Trigger功能在Insert時產生流水號。
如果要先看到單號,那就可以利用 SQL Transition 功能確認產生取得方式。

作者: checkbox4    時間: 2017-12-29 02:19 AM

您需要的是database層次的lock 而不是程式碼的lock
序號或流水號問題 使用資料庫技術比較容易解決
作者: sunneo    時間: 2018-1-21 03:14 AM

C#的lock的使用要小心喔
建議lock物件是object且不可以是會被修改的物件,
因為當你的物件內容變了,那個lock可能會失效,比方說當你lock的對象是list、或者可以被dispose的物件。

https://docs.microsoft.com/zh-tw ... ords/lock-statement

如果你不想要使用區塊式的lock語法,那麼你可以用Monitor.Enter,Monitor.Exit來確保程式操作是在一個Monitor操作區間








歡迎光臨 伊莉討論區 (http://www545675.eyny.com/) Powered by Discuz!