C#同步对象 - 与写入访问器重复的代码

时间:2009-03-19 16:04:09

标签: c# multithreading synchronization

我喜欢使用在更改属性时锁定的私有对象同步自身的对象。 有没有通用的方法来实现这一目标? 对于每个属性(带有一个更衣室对象),我的代码看起来总是如此

private Object locker = new Object();
private int x; 
    public int X
    {
    get {return x;} 
    set{
        lock(locker){x=value;}
    }

这是一种更简单的方法来实现线程安全的属性修改。

3 个答案:

答案 0 :(得分:8)

您的代码不应该是这样 - 您也应该锁定 get 。否则,由于内存模型的复杂原因,获取数据的线程可能无法获得最新值。

但不,我不知道有什么方法可以解决这个问题。你可以用lambda表达式和扩展方法做奇怪的事情,但这对IMO来说太过分了。

您还应该强烈考虑是否希望各个属性是线程安全的。这可能是正确的做法 - 但我发现通常我不需要大多数类型的线程安全。只有少数类型需要直接了解线程,然后他们在使用对象时取出适当的锁,而不是执行锁定的对象。这取决于你正在做什么。

某些情况的另一种选择是使用不可变类型 - 当你可以使用它时很好,尽管如果你需要一个线程来查看在另一个线程中所做的更改,你需要一些类型的波动性或同步。

答案 1 :(得分:3)

不要成为'推动者',但如果您认为这绝对是您想要的设计,并且您发现自己重复输入这些属性,那么您可能需要节省一些按键并编写一些代码片段来加速添加它们的过程。

    <?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>prop</Title>
            <Shortcut>propso</Shortcut>
            <Description>Locking property for SO</Description>
            <Author>TheMissingLinq</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
                    <ToolTip>Field Name</ToolTip>
                    <Default>myField</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp">
            <![CDATA[private $type$ $field$;
                public $type$ $property$ 
                {
                    get
                    {
                        lock(locker) { return this.$field$; }
                    }
                    set
                    { 
                        lock(locker) { this.$field$ = value; } 
                    }
                }
            $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

答案 2 :(得分:2)

我一直惊讶于C#可以用新的C#3.0功能做些什么。我打算把那些东西扔到那里我以为会马虎虎虎,但事实证明它比我希望的要好。这是'。

使一个对象保存所有值(让我们称之为“价值持有者”......不要与该术语的任何其他用法相混淆)。它只有C#自动属性。然后创建另一个对象,以访问值持有者。将第二个对象称为“SynchronicityHandler”(sucky term,但会得到概念)。

让SynchronicityHandler进行锁定。它现在可以是通用的。所以这就是你得到的:

public class PersonValueHolder
{
     public string FirstName { get; set; }
     public string LastName { get; set; }
     public bool HasCollegeDegree { get; set; }
}

public class SyncronicityHandler<T>
{
     private object locker = new object();

     private T valueHolder;

     public SynchronicityHandler(T theValueHolder)
     {
          this.valueHolder = theValueHolder;
     }

     public void WorkWithValueHolderSafely(Action<T> yourAction)
     {
          lock(locker)
          {
               yourAction(valueHolder);
          }
     }
}

以下是您如何称呼它的示例:

var myPerson = new SynchronicityHandler(new PersonValueHolder());

// Safely setting values
myPerson.WorkWithValueHolderSafely( p => 
     {
          p.FirstName = "Douglas";
          p.LastName = "Adams";
          p.HasCollegeDegree = true;
     });

// Safely getting values (this syntax could be improved with a little effort)
string theFirstName = null;

myPerson.WorkWithValueHolderSafely( p=> theFirstName = p.FirstName);

Console.Writeline("Name is: " + theFirstName); // Outputs "Name is: Douglass".

真的,现在我想到了,“价值持有者”不一定只是自动属性。它可以是任何物体。