2009-08-12 107 views
0

我的問題是,如果我使用多線程上相同的字符串有時訪問使用多線程相同的字符串(StringBuilder)對

字符串將不會進行更換。(我寫了這個記事本上這樣的語法可能

使用錯誤)

System.Thread ...其他ofcourse

class .... 
{ 
    private static StringBuild container = new StringBuilder(); 

    static void Main(...) 
    { 
    container.Append(Read From File(Kind of long)); 
    Thread thread1 = new Thread(Function1); 
     Thread thread2 = new Thread(Function2); 
    thread1.Start(); 
    thread2.Start(); 
    //Print out container 
    } 

    static void Function1 
    { 
    //Do calculation and stuff to get the Array for the foreach 
    foreach (.......Long loop........) 
    { 
    container.Replace("this", "With this") 
    } 
    } 
    //Same goes for function but replacing different things. 
    static void Function2 
    { 
    //Do calculation and stuff to get the Array for the foreach 
    foreach (.......Long loop........) 
    { 
    container.Replace("this", "With this") 
    } 
    } 
} 

現在有時一些元素沒有得到更換。 所以我的解決方案是調用container.Replace在不同的

方法,並做一個「鎖」哪個工作,但它是正確的方式?

private class ModiflyString 
{ 
     public void Do(string x, string y) 
      { 
       lock (this) 
       { 
        fileInput.Replace(x, y); 
       } 
      } 
} 

回答

5

您應該鎖定StringBuilder對象本身(內部的替換功能):

lock (container) 
{ 
    container.Replace("this", "With this"); 
} 

或創建一個單獨的鎖定對象:

static object _stringLock = new object(); 

... 

lock(stringLock) 
{ 
    container.Replace("this", "With this"); 
} 
+0

我從來沒有想過鎖定stringbuilder本身,非常好。謝謝, – 2009-08-12 20:26:08

+0

菲爾的第二個例子就是當我提到一個「虛擬」對象時所指的。然而,我認爲他第一個鎖定容器的例子是他們中最好的。由於容器表示線程之間共享的數據,因此您需要鎖定該數據。如果您使用我的示例,則存在以下問題:如果您的線程嘗試爲完全獨立的容器調用ModifyString.Do,則它們將相互阻塞,即使它們所使用的容器完全不同。所以你會傷害表現。所以我的例子實際上是一個糟糕的實現。 – AaronLS 2009-08-12 20:28:39

+0

感謝@arronls現在我的程序正在工作:) – 2009-08-12 20:39:29

3

當你創建超過1個ModifyString對象時,你的鎖定將不起作用,我猜你會這樣做。

一個簡單的版本:

public void Do(string x, string y) 
    { 
     lock (fileInput) 
     { 
     fileInput.Replace(x, y); 
     } 
    } 

這可能是最好創建一個單獨的對象做鎖定,但上面顯示的原則更好:所有競爭性線程應該在同一對象上鎖定。

的標準方法看起來像:

private static StringBuild container = new StringBuilder(); 
private static object syncLock = new object(); // simple object, 1-1 with container 

,然後你可以(thread-)安全使用:

lock(syncLock) 
    { 
     container.Replace(...); 
    } 
+0

我確實創建了一個對象,這就是爲什麼我能夠使用「this」 – 2009-08-12 20:17:58

+0

但是您是否實例化了_only_ 1?這就是我想說的。 – 2009-08-12 20:20:23

+1

不,您創建了_many_ objects- ModifyString的每個實例都是它自己的對象。 – 2009-08-12 20:20:25

2

只要兩個線程都具有相同的ModifyString類實例,這樣就可以正常工作。換句話說,這將工作,因爲上了鎖「這個」必須在同一個實例的鎖:

class Blah 
{ 
    private static StringBuild container = new StringBuilder(); 

    private static ModifyString modifyString = new ModifyString(); 

    static void Main(...) 
    { 
    container.Append(Read From File(Kind of long)); 
    Thread thread1 = new Thread(Function1); 
     Thread thread2 = new Thread(Function2); 
    thread1.Start(); 
    thread2.Start(); 
    //Print out container 
    } 

    static void Function1 
    {  

     //Do calculation and stuff to get the Array for the foreach 
     foreach (.......Long loop........) 
     { 
      modifyString.Do("this", "With this") 
     } 
    } 
    //Same goes for function but replacing different things. 
    static void Function2 
    { 
     //Do calculation and stuff to get the Array for the foreach 
     foreach (.......Long loop........) 
     { 
      modifyString.Do("this", "With this") 
     } 
    } 
} 

它將工作,如果你做了下面的,因爲鎖(這)是行不通的某種意義上,他們是兩個不同的實例:

class Blah 
{ 
    private static StringBuild container = new StringBuilder(); 

    static void Main(...) 
    { 
    container.Append(Read From File(Kind of long)); 
    Thread thread1 = new Thread(Function1); 
     Thread thread2 = new Thread(Function2); 
    thread1.Start(); 
    thread2.Start(); 
    //Print out container 
    } 

    static void Function1 
    { 
     ModifyString modifyString = new ModifyString(); 
     //Do calculation and stuff to get the Array for the foreach 
     foreach (.......Long loop........) 
     { 
      modifyString.Do("this", "With this") 
     } 
    } 
    //Same goes for function but replacing different things. 
    static void Function2 
    { 
     ModifyString modifyString = new ModifyString(); 

     //Do calculation and stuff to get the Array for the foreach 
     foreach (.......Long loop........) 
     { 
      modifyString.Do("this", "With this") 
     } 
    } 
} 

有些人會真正創建一個「虛擬」的對象上,而不是用「本」(你不能串鎖進行鎖定,因爲它是值類型)。

+0

StringBuilder不是一個值類型,你知道嗎? – 2009-08-12 20:32:31

+0

我沒有說絃樂器,我說絃樂。 – AaronLS 2009-08-12 20:37:28