想我會發佈一個完整的代碼示例B/C一些事情可能會非常棘手。
public class MyIntIncrementer
{
public int MyInt = 0;
}
public static String TimeStamp
{
get { return DateTime.UtcNow.ToString("HH:mm:ss.fff"); } //yyyy-MM-dd
}
public static void Main(string[] args)
{
List<Task<string>> tasks = new List<Task<string>>();
int waitSeconds = 5;
Console.WriteLine(String.Format("{0}: Start", TimeStamp));
DateTime start = DateTime.Now;
MyIntIncrementer iIncrementer = new MyIntIncrementer();
iIncrementer.MyInt = 0;
for (int i = 0; i < 10; i++)
{
//definitely loops and changes values - but when passed in to the function they don't remain that way... see iParam
//Console.WriteLine(String.Format("{0}: Looping... i: {1}\n", TimeStamp,i));
tasks.Add(Task.Run(() =>
{
// all have 10 => last value :(
// Console.WriteLine(String.Format("{0}: Running... i: {1}\n", TimeStamp, i));
return SayYesIfEven(waitSeconds, i, iIncrementer);
}));
}
Console.WriteLine(String.Format("{0}: Before Wait...", TimeStamp));
// wait for them to run
Task.WhenAll(tasks).Wait();
//Task.WhenAll(tasks); // doesn't wait with .Wait()
Console.WriteLine(String.Format("{0}: After Wait... Results:", TimeStamp));
// get the results
for (int i = 0; i < tasks.Count; i++)
{
Console.WriteLine(tasks[i].Result);
}
Console.WriteLine(String.Format("{0}: Done ({1}s)", TimeStamp, (DateTime.Now - start).TotalSeconds));
}
public static async Task<string> SayYesIfEven(int waitSeconds, int iParam, MyIntIncrementer iIncrementer)
{
int localIParamStart = (int)iParam; // no difference from passed in value when copied locally
int currentIStart = iIncrementer.MyInt; // not guaranteed to be unique
// iParam is the last value and when 'iIncrementer.MyInt' prints here, it's sometimes the same in multiple threads
Console.WriteLine(String.Format("{0:00}: Before Increment: even? {1} <=> {2:00}/iP: {3:00}/LiP: {4:00}/in.mP: {5:00}", TimeStamp, (currentIStart % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt));
// best way to get a unique value
int currentIR = Interlocked.Increment(ref iIncrementer.MyInt); // all threads wait on a lock to increment and then they move forward with their own values
int currentI = iIncrementer.MyInt;
int localIParam = (int)iParam;
Console.WriteLine(String.Format("{0:00}: After Increment: even? {1} <=> {2:00} => {6:00} => {7:00}/iP: {3:00}/LiP: {4:00} => {8:00}/in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
await Task.Delay(waitSeconds * 1000); // simulate delay
await Task.Run(() =>
{
// do other stuff...
// iParam and iIncrementer.value have the last value (note that this statement runs after the above delay)
Console.WriteLine(String.Format("{0:00}: Inside Run after Delay: even? {1} <=> {2:00} => {6:00} => {7:00}/iP: {3:00}/LiP: {4:00} => {8:00}/in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
return "something";
});
// all have last value when showing what was passed into SayYesIfEven - and iIncrementer.value is also the last value
return (String.Format("{0:00}: Returning: even? {1} <=> {2:00} => {6:00} => {7:00}/iP: {3:00}/LiP: {4:00} => {8:00}/in.mP: {5:00}", TimeStamp, (currentI % 2 == 0 ? "Yes" : "No "), currentIStart, iParam, localIParamStart, iIncrementer.MyInt, currentIR, currentI, localIParam));
}
輸出:
13:55:35.340: Start
13:55:35.357: Before Wait...
// rearranged to show before/after values side by side
// note the duplicate values for MyIntIncrementer.MyInt - and last values for iParam
13:55:35.357: Before Increment: even? Yes <=> 00/iP: 10/LiP: 10/in.mP: 00
13:55:35.357: Before Increment: even? Yes <=> 00/iP: 10/LiP: 10/in.mP: 00
13:55:35.371: Before Increment: even? Yes <=> 02/iP: 10/LiP: 10/in.mP: 02
13:55:35.371: Before Increment: even? No <=> 03/iP: 10/LiP: 10/in.mP: 03
13:55:35.371: Before Increment: even? Yes <=> 04/iP: 10/LiP: 10/in.mP: 04
13:55:35.371: Before Increment: even? No <=> 05/iP: 10/LiP: 10/in.mP: 05
13:55:35.371: Before Increment: even? Yes <=> 06/iP: 10/LiP: 10/in.mP: 06
13:55:35.371: Before Increment: even? No <=> 07/iP: 10/LiP: 10/in.mP: 07
13:55:35.371: Before Increment: even? No <=> 07/iP: 10/LiP: 10/in.mP: 07
13:55:35.371: Before Increment: even? Yes <=> 00/iP: 10/LiP: 10/in.mP: 00
// after the locked increment, notice we have reliable independent values
13:55:35.371: After Increment: even? Yes <=> 00 => 02 => 02/iP: 10/LiP: 10 => 10/in.mP: 02
13:55:35.371: After Increment: even? No <=> 00 => 01 => 01/iP: 10/LiP: 10 => 10/in.mP: 01
13:55:35.371: After Increment: even? No <=> 02 => 03 => 03/iP: 10/LiP: 10 => 10/in.mP: 03
13:55:35.371: After Increment: even? Yes <=> 03 => 04 => 04/iP: 10/LiP: 10 => 10/in.mP: 04
13:55:35.371: After Increment: even? No <=> 04 => 05 => 05/iP: 10/LiP: 10 => 10/in.mP: 05
13:55:35.371: After Increment: even? Yes <=> 05 => 06 => 06/iP: 10/LiP: 10 => 10/in.mP: 06
13:55:35.371: After Increment: even? No <=> 06 => 07 => 07/iP: 10/LiP: 10 => 10/in.mP: 07
13:55:35.371: After Increment: even? Yes <=> 07 => 08 => 08/iP: 10/LiP: 10 => 10/in.mP: 08
13:55:35.371: After Increment: even? No <=> 07 => 09 => 09/iP: 10/LiP: 10 => 10/in.mP: 09
13:55:35.371: After Increment: even? Yes <=> 00 => 10 => 10/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? Yes <=> 07 => 08 => 08/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? Yes <=> 05 => 06 => 06/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? No <=> 07 => 09 => 09/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? No <=> 04 => 05 => 05/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? No <=> 02 => 03 => 03/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? No <=> 00 => 01 => 01/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? Yes <=> 00 => 10 => 10/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? Yes <=> 00 => 02 => 02/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? Yes <=> 03 => 04 => 04/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Inside Run after Delay: even? No <=> 06 => 07 => 07/iP: 10/LiP: 10 => 10/in.mP: 10
// notice at the bottom of the call - MyIntIncrementer.MyInt is the last value and thus never unique
// - only the initial value (obtained after the lock and before any delay) is still reliable - same behavior found on a 100+ loop
13:55:40.381: After Wait... Results:
13:55:40.381: Returning: even? Yes <=> 00 => 10 => 10/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? No <=> 00 => 01 => 01/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? Yes <=> 00 => 02 => 02/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? No <=> 02 => 03 => 03/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? Yes <=> 03 => 04 => 04/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? No <=> 04 => 05 => 05/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? Yes <=> 05 => 06 => 06/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? No <=> 06 => 07 => 07/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? Yes <=> 07 => 08 => 08/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Returning: even? No <=> 07 => 09 => 09/iP: 10/LiP: 10 => 10/in.mP: 10
13:55:40.381: Done (5.0410934s)
能否請您告訴我們您的問題的一個簡單而完整的再現? [這](http://tryroslyn.azurewebsites.net/#f:r/K4Zwlgdg5gBAygTxAFwKYFsDcAoUlaIoYB0AKgBYBOqAhgCb5k0gDWIOe08Sa6ZVtBtBzYADsABGAGzABjGLKnMQMAMIwA3thg6Y46XJjMEEeaWYsYAWQAUASk3bdzyMhhgYAXhgAGHM+caAHcaMDdzVmIATTBUKTp7fwCdAEkINEopAHtZFlQ6YjTZanRUdJtqADN3OySdAF9seqAA=)工作正常。 –
爲此目的使用包裝類有什麼問題?只用一個'int'字段創建一個類。 –
我似乎記得.net框架有專門爲您正在描述的內容而設計的類。也許在任務並行庫中?或者,您可以鎖定Object的實例。正如@AndreyNasonov所評論的,你可以在包裝類中實現它。 – Bovaz