2015-09-14 78 views
7

後不更新尋找在這個代碼:值異步方法恢復

public class SharedData 
{ 
    public int Value { get; set; } 
} 

void button1_Click(object sender, EventArgs e) 
{ 
    AAA(); 
} 

async Task BBB(SharedData data) 
{ 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    MessageBox.Show(data.Value.ToString()); //<---- I always see 0 here, 
    data.Value = data.Value + 1; 
} 

async Task<int> AAA() 
{ 
    SharedData data = new SharedData(); 
    var task1 = BBB(data); 
    var task2 = BBB(data); 
    var task3 = BBB(data); 

    await Task.WhenAll(task1, task2, task3); 
    MessageBox.Show(data.Value.ToString()); //<--- this does show 3 
    return data.Value; 
} 

這是一個GUI(窗口形式)應用程序,這意味着只有一個執行的代碼的每一行線程。

全部BBB(data)調用非常快速地調用,無需等待。 每個BBB調用進入BBB method,看到await不完成並返回(到AAA)。

現在,當一秒(大約)已過時,在GUI線程中所有延續發生

問題

延續,因爲它是一個GUI線程不會同時發生。 因此,以前的聲明:

data.Value = data.Value + 1; 

必須發生。

換句話說,

我知道,所有BBB s的與data相同的初始值調用,但延續不會發生同時

GUI線程必須最終運行:

延續#1

MessageBox.Show(data.Value.ToString()); 
data.Value = data.Value + 1; //So this basically should do 0-->1 
.... 

延續#2

MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ?? 
data.Value = data.Value + 1; 
.... 

延續#3

MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ?? 
data.Value = data.Value + 1; 

它看起來像延續預計不會作爲一個整體,但作爲共享量子?

+0

@Eser我不明白,每次延續了自己的gui線程。這裏有**沒有**其他線程。爲什麼鎖定?這不是(!)在線程池線程中運行,這意味着沒有上下文可以保留(並且每個延續可以在另一個線程池線程中運行)。 –

+0

更改'BBB'以接受並使用延遲值:'異步任務BBB SharedData data,int delay)',然後傳遞不同的值而不是相同的'1'。想知道爲什麼現在你一次看到三個消息框,而不是一次一個? :) – Noseratio

+0

@Noseratio是的,我不知道:-)你能解釋一下嗎? [此代碼](http://i.imgur.com/pWUXCXW.png)一起顯示3 MSgBox,而不是1(如我的示例中)。你能解釋爲什麼嗎? –

回答

5

發生這種情況是因爲您正在使用MessageBox.Show進行調試打印,並顯示模式消息框會阻止代碼流,但不會阻止UI線程(否則無法與消息框進行交互)。

因此,當第一個延續通過顯示一個消息框「封鎖」時,下一個延續可以運行,然後是第三個延續。他們都通過顯示消息框被「屏蔽」,但UI線程本身不是。

這就是爲什麼他們都顯示0,只有當你釋放消息框時,他們可以繼續運行並增加變量。

你可以看到,如果你顯示消息框之前打印使用Console.WriteLine值:

async Task BBB(SharedData data) 
{ 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    Console.WriteLine(data.Value); 
    MessageBox.Show(data.Value.ToString()); 
    data.Value = data.Value + 1; 
} 

你會發現,0由所有延續正好1秒後,而不是在你打印3倍關閉消息框。

基本上,延續併發運行,但不是並行使用相同的線程因爲其中的MessageBox.Show

如果您使用的Console.WriteLine代替MessageBox.Show你會看到該值在時間增加一個:

async Task BBB(SharedData data) 
{ 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    Console.WriteLine(data.Value); 
    data.Value = data.Value + 1; 
} 

輸出:

0 
1 
2 
+0

第二段不清楚(對我來說)。 :_當第一次繼續通過顯示一個消息框被「阻止」時,下一次繼續可以運行,然後第三次?你可以請示步驟嗎? –

+0

@RoyiNamir顯示一個模式消息框阻止當前的代碼流,但它不會通過阻塞線程(否則應用程序將凍結)來實現。這意味着第一個延續卡住了,但下一個可以在UI線程上運行。 – i3arnon

+0

因此,當我看到第一個消息框時,那時已經有2個繼續,它們已經調用了'MessageBox.Show(data.Value.ToString());',其中未提高值? –