2011-01-10 82 views
0

假設從ASP.NET頁面調用如下的靜態方法, 可以在線程(a)執行第一行後,不同的線程(b)覆蓋s1的值, ?傳遞給靜態方法的參數中的線程安全

如果是這樣,可以在操作解決此問題之前將參數分配給局部變量?

public static string TestMethod(string s1, string s2, string s3) 
{ 
    s1 = s2 + s3; 
    .... 
    ... 
    return s1; 
} 

是否有一個簡單的方法來重新創建這樣的線程安全相關的問題?

謝謝。

回答

0

,在某些情況下,如示例代碼所示。

public static class ConsoleApp { 
    public static void Main() { 
     Console.WriteLine("Write something."); 
     var str = Console.ReadLine(); 
     if (String.IsNullOrEmpty(str)) 
      return; 

     new Thread(() => TestMethod(null, str, "")).Start(); 

     // Allow TestMethod to execute. 
     Thread.Sleep(100); 

     unsafe { 
      // Grab pointer to our string. 
      var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned); 
      var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer(); 

      // Change it, one character at a time, wait a little more than 
      // TestMethod for dramatic effect. 
      for (int i = 0; i < str.Length; ++i) { 
       strPtr[i] = 'x'; 
       Thread.Sleep(1100); 
      } 
     } 

     // Tell TestMethod to quit. 
     _done = true; 
     Console.WriteLine("Done."); 
     Console.ReadLine(); 
    } 

    private static Boolean _done; 
    public static void TestMethod(String x, String y, String z) { 
     x = y + z; 

     while (!_done) { 
      Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), x); 
      Thread.Sleep(1000); 
     } 
    } 
} 

要求(AFAIK)

  1. 不安全上下文使用指針。
  2. 使用String.Concat(String str0,String str1),它針對str0 == String.Emptystr1 == String.Empty(返回非空字符串)的情況進行了優化。連接三個或更多的字符串會創建一個新的字符串來阻止它。

這裏是你修改的一個固定的版本。

public static class ConsoleApp { 
    private static Int32 _counter = 10; 

    public static void Main() { 
     for (var i = 0; i < 10; i++) { 
      var str = GetString(); 
      Console.WriteLine("Input: {0} - {1}", DateTime.Now.ToLongTimeString(), str); 
      new Thread(() => TestMethod(str)).Start(); 

      unsafe { 
       var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned); 
       var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer(); 
       strPtr[0] = 'A'; 
       strPtr[1] = 'B'; 
       strPtr[2] = 'C'; 
       strPtr[3] = 'D'; 
       strPtr[4] = 'E'; 
      } 
     } 

     Console.WriteLine("Done."); 
     Console.ReadLine(); 
    } 

    private static String GetString() { 
     var builder = new StringBuilder(); 

     for (var i = _counter; i < _counter + 10; i++) 
      builder.Append(i.ToString()); 

     _counter = _counter + 10; 
     return builder.ToString(); 
    } 

    public static void TestMethod(Object y) { 
     Thread.Sleep(2000); 
     Console.WriteLine("Output: {0} {1}", DateTime.Now.ToLongTimeString(), y); 
    } 
} 

這仍然有效,因爲Object.ToString()的字符串被重寫以返回此信息,並返回完全相同的參考。

4

不,參數是局部變量 - 它們獨立於任何其他線程。由於字符串也是不可變的,所以你很安全。如果這些是可變的 - 例如參數StringBuilder s1 - 儘管s1(引用)的無法更改,但所引用參數的對象可能會更改其內容。

refout參數可能會有問題,因爲它們可以別名在線程之間共享的變量。

+0

謝謝..參數是局部變量並且獨立於其他線程。但有沒有簡單的方法來重新創建/調試這些問題? – humblelistener 2011-01-10 18:57:39

+0

@Pkay:我通常不會,恐怕。線程錯誤很難跟蹤和測試:( – 2011-01-10 19:15:33

0

謝謝西蒙,這裏是我對此的評價。 在下面的代碼中,我簡單地使用Thread.Start生成線程,輸出變得不一致。

這證明可以修改傳遞給方法的字符串。

如果不然請說明

public static class ConsoleApp{ 

    [ThreadStatic] 
    private static int counter = 10; 

    public static void Main() 
    {    
     string str; 

     object obj = new object(); 
     // Change it, one character at a time, wait a little more than 
     // TestMethod for dramatic effect.    
     for (int i = 0; i < 10; i++) 
     { 
      lock (obj) 
      { 
       str = GetString(); 
       Console.WriteLine(DateTime.Now.ToLongTimeString()); 
       //ThreadPool.QueueUserWorkItem(TestMethod, str); 
       new Thread(() => TestMethod(str)).Start(); 
      } 
     } 

     Console.WriteLine("Done."); 
     Console.ReadLine(); 
    } 

    private static string GetString() 
    { 
     object obj = new object(); 
     lock (obj) 
     { 
      StringBuilder sb = new StringBuilder(); 
      int temp = 0; 
      for (int i = counter; i < counter + 10; i++) 
      { 
       sb.Append(i.ToString()); 
       temp = i; 
      } 
      counter = temp;    
      return sb.ToString(); 
     } 
    } 

    public static void TestMethod(object y) 
    { 
     Thread.Sleep(2000); 
     Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), y.ToString()); 
    } 
} 

謝謝。

1

我也有同樣的困惑,這裏是我的測試代碼。公正地分享它...

public partial class _default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     ThreadTest b = new ThreadTest(); 
     Thread t = new Thread(new ParameterizedThreadStart(ThreadTest.sum)); 
     Thread t1 = new Thread(new ParameterizedThreadStart(ThreadTest.sum)); 
     t.Start(10); 
     t1.Start(12); 

    } 
} 

class ThreadTest 
{ 

    public static void sum(object XX) 
    { 
     int x = (int)XX; 
     for (int i = 0; i < x; i++) 
     { 
      System.Diagnostics.Debug.WriteLine("max : " + x + " --- " + i.ToString()); 
     } 
    } 
} 

...現在,如果你運行這個,你會看到這個int x是安全的。因此局部非靜態變量對於一個進程是安全的,並且不能被多個線程癱瘓