亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

在多線程程序中未讀取正確的屬性值

在多線程程序中未讀取正確的屬性值

C#
幕布斯6054654 2023-06-25 13:54:41
我遇到了一種情況,我不確定為什么我在多個線程中沒有從屬性中讀取正確的屬性值。我編寫了一個小型控制臺應用程序來說明這種情況class Program{    private static Test MyObject;    static void Main(string[] args)    {        MyObject = new Test();        Task.Run(() =>        {            var obj = MyObject as Test;            Console.WriteLine("1: " + obj.MyValue);            Update("Thread1");            Console.WriteLine("2: " + obj.MyValue);        });        Task.Run(() =>        {            var obj = MyObject as Test;            Console.WriteLine("3: " + obj.MyValue);            Thread.Sleep(100);            Update("Thread2");            Console.WriteLine("4: " + obj.MyValue);        });        void Update(string val)        {            lock (MyObject)            {                MyObject.MyValue = val;            }        }        Thread.Sleep(400);        Console.WriteLine("5: " + MyObject.MyValue);    }}class Test{    public string MyValue { get; set; }}運行上面的行我得到這個輸出1:2: Thread13:4: Thread25: Thread2我的期望是“3:”應該始終顯示“3:Thread1”,因為同一對象已較早更新。但事實并非如此,我不確定我在這里缺少什么......有人可以解釋一下嗎?只是一個小注意...如果您運行代碼并得到不同的順序,請重新運行它...我只對上面的順序感興趣。
查看完整描述

1 回答

?
慕田峪7331174

TA貢獻1828條經驗 獲得超13個贊

有幾件事:

  1. 您的Update()方法將寫入同步屬性MyValue,但對讀取不執行任何操作。因此,運行時可以自由地使用對象的緩存值。這不太可能與您觀察到的輸出有任何關系,因為實際上您不太可能看到這一點,尤其是在 x86 硬件上。但…

  2. 更重要的是,您的代碼所展示的只是輸出順序可能會產生誤導。該類Console具有同步功能以確保來自多個線程的一致輸出,但是代碼中沒有任何內容可以確保如果按特定順序寫入輸出行,則導致這些輸出行的代碼(例如讀取屬性)MyValue發生與這些輸出行的顯示順序相同。

換句話說,僅僅因為控制臺"2:"在該行之前顯示了該行"3:",實際上并不意味著對的調用發生Update("Thread1")在對Console.WriteLine("3: " + obj.MyValue);

lock如果您想確保輸出行與程序中語句的執行順序相匹配,您還需要使用語句來保護各個操作。

更具體地說,請考慮以下可能的代碼執行順序:

thread 1                                      thread 2

--------                                      --------

                                              "value" parameter <= "3: " + obj.MyValue

Console.WriteLine("1: " + obj.MyValue);

Update("Thread1");

Console.WriteLine("2: " + obj.MyValue);

                                              Console.WriteLine(value);

Console.WriteLine()即,在第一個線程開始其邏輯之前,第二個線程計算傳遞給的參數是完全合法的。但是,第一個線程也可以在第二個線程有機會實際調用該Console.WriteLine()方法之前搶占第二個線程。


如果發生這種情況,您會看到線程 1 的預期輸出順序,但線程 2 的輸出寫入該屬性的明顯過時版本MyValue,因為它是在線程 1 運行其任何邏輯之前檢索到的。


為了解決該特定場景,您可以使用lock呼叫WriteLine()。例如:


lock (MyObject) Console.WriteLine("1: " + obj.MyValue);

請注意,您需要將其放在每次調用Console.WriteLine(). 這將確保寫入控制臺的任何值都是調用時屬性的最新值。


查看完整回答
反對 回復 2023-06-25
  • 1 回答
  • 0 關注
  • 118 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號