2015-09-08 83 views
1

考慮下面的代碼:將Task作爲方法參數傳遞是否安全?

public class Program { 
    static void Main(string[] args) { 
     Generate(); 
    } 

    static void Generate() { 
     Task t = null; 
     t = Task.Run(() => { 
      MyClass myClass = new MyClass(); 
      myClass.ContinueTask(t); 
     }); 
     Console.ReadLine(); 
    } 
} 
public class MyClass { 

    public void ContinueTask(Task t) { 
     t.ContinueWith(x => { 
      Console.WriteLine("Continue here..."); 
     }); 
    } 
} 

它是安全與T傳遞的參數作爲這樣還是更直接啓動內部MyClass的一個新的任務?

+1

這看起來並不安全 - 因爲內部任務已經開始並且已經在't'分配發生之前到達'Read' *調用的可能性很小。 –

+0

@Damien_The_Unbeliever避免這種情況的方法是什麼?我使用的是ContinueWith,這聽起來像你必須讓對象本身繼續對它做某些事情。 – Hristo

+0

這似乎是幾乎遞歸的。除非我錯過了一些東西,這就是說在讀取之後繼續解析,這需要解析作爲讀取的一部分。 – Enigmativity

回答

1

這是不安全的,因爲t可能不會在使用它的地方被分配。事實上,這是一場數據競賽。

即使您修復它會是壞的體系結構。爲什麼ContinueTask需要知道它正在繼續。這不是一個應該放在這裏的問題。 ContinueTask應該執行它的工作,假設它的先行者已經完成。

很難說出你要完成什麼。按如下順序排列代碼有什麼問題:?

static async Task Generate() { 
    var t = Task.Run(() => { 
    //... other code ... 
    }); 

    MyClass myClass = new MyClass(); 
    await t; 
    myClass.ContinueTask(); 

    Console.ReadLine(); 
} 

await非常適合測序任務。

重用Task對象

你是什麼意思?任務不能重複使用。它不能運行兩次。你的ContinueWith所做的就是在邏輯上等待前件,然後運行lambda。在這裏,任務基本上是一個事件。

ContinueWith不會修改它被調用的任務。它創建了一項新任務。

+0

@克里斯你能說什麼特別有助於這個答案?我沒有完全理解你正在努力解決的問題。 – usr

+0

未檢查ContinueWith上的文檔。調用這個方法ConitnueWith在任務上是有意義的,如果它是執行動作的同一個對象(至少對我來說),因此調用ConitnueWith對於判斷前一個任務的工作是否有意義(同一個對象任務) – Hristo

+1

是的,任務是種不可改變的。不變性在多線程設置中特別有用。另外,寧願繼續等待ContinueWith。儘管幾乎相同,但使用起來更容易。 – usr

1

我已經減少了你的代碼到這個例子:

public Task<int> Parse() 
{ 
    Task<int> t = null; 
    t = Task.Run(() => this.Read(t)); 
    return t; 
} 

public Task<int> Read(Task<int> t) 
{ 
    return t.ContinueWith(v => 42); 
} 

我認爲有相同的底層結構。

這會導致死鎖。我懷疑你的代碼也是。所以我認爲這是不安全的。

+0

他沒有回't'。 – usr

+1

@usr - Cricky,他改變了他的密碼。原本他回來了't'。 – Enigmativity

+0

@usr最初有一個返回語句。造成僵局確實是一個問題,但這不是我問題的重點。重點在於重用Task對象。 – Hristo

相關問題