C# 如何将方法标记为非线程安全?

C# 如何将方法标记为非线程安全?,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,我偶尔会碰到这个问题而忽略它,但它今天开始折磨我 private readonly object _syncRoot = new object(); private List<int> NonconcurrentObject { get; } = new List<int>(); public void Fiddle() { lock (_syncRoot) { // ...some code... Nonconcurr

我偶尔会碰到这个问题而忽略它,但它今天开始折磨我

private readonly object _syncRoot = new object();

private List<int> NonconcurrentObject { get; } = new List<int>();

public void Fiddle()
{
    lock (_syncRoot)
    {
        // ...some code...
        NonconcurrentObject.Add(1);
        Iddle();
    }
}

public void Twiddle()
{
    lock (_syncRoot)
    {
        // ...some different code...
        NonconcurrentObject.Add(2);
        Iddle();
    }
}

private void Iddle()
{
    // NOT THREADSAFE! DO NOT CALL THIS WITHOUT LOCKING ON _syncRoot
    // ......lots of code......
    NonconcurrentObject.Add(3);
}
private只读对象_syncRoot=new object();
私有列表非当前对象{get;}=new List();
公共小提琴
{
锁定(\u syncRoot)
{
//…一些代码。。。
非当前对象。添加(1);
Iddle();
}
}
公共空间旋转()
{
锁定(\u syncRoot)
{
//…一些不同的代码。。。
非当前对象。添加(2);
Iddle();
}
}
私有无效Iddle()
{
//非线程安全!在未锁定\u syncRoot的情况下,请勿调用此
//……很多代码。。。。。。
非当前对象。添加(3);
}
我有一个类的多个公共方法,其中一些代码本身不是线程安全的(上面的
列表是一个简单的例子)。我想对它们之间共享的代码使用helper方法(任何人都会这样),但在分离共享代码时,我面临一个两难的问题:我是否在helper方法中使用递归锁定?如果我这样做了,我的代码是浪费的,而且可能会降低性能。如果我不这样做(如上所述),那么helper方法不再是线程安全的,如果将来被其他方法调用,它将面临恶劣的竞争条件

我如何(优雅而有力地)表示某个方法不是线程安全的?

您可以使用文档注释

///<remarks>not thread safe</remarks>
///不是线程安全的

您可以使用自定义属性来标记非线程安全的方法

与注释相比,它的优势在于,如果您希望在以后进行进一步处理,它可以为您提供选项(通过反射)

public class NotThreadSafe : Attribute
{
    //...
}

public class MyClass
{
    [NotThreadSafe]
    public void MyMethod()
    {
        //...
    }
}

您可以将
\u Unsafe
后缀添加到不受锁保护的实用程序方法中

优点:它提醒你正在做危险的事情,因此你必须格外小心。一个小错误可能会使您在将来花费数天的调试时间

缺点:不太漂亮,可能与关键字混淆

private void Iddle_Unsafe()
{
    NonconcurrentObject.Add(3);
}

public void Twiddle()
{
    lock (_syncRoot)
    {
        NonconcurrentObject.Add(2);
        Iddle_Unsafe();
    }
}

你知道吗。这就是答案。我在这里真是太可笑了。我更喜欢这个答案,因为创建一个属性来标记一个方法会向我传达一些与该属性相关的软行为。MSDN提供了特定类是线程安全的还是非线程安全的文档。文档。您可以使用自定义属性和Roslyn分析器,但这可能有点过分,具体取决于场景。@yaakov:我很乐意看到这个答案。不过您的示例并不正确。为什么一个函数不是线程安全的,而其他函数是线程安全的,尽管它们处理的是同一个object.XY问题。只需使用线程安全collection@MickyD只有在集合的内部状态是您必须保护的唯一共享状态的情况下,使用线程安全集合才是可行的。因为线程安全集合只能保证:它的内部状态的完整性。当您必须执行任何复杂的操作时,通常会被迫执行手动同步,因为还有其他需要保护的共享状态。对我来说,这种方法会传递一种与使用属性标记方法相关的行为,因为该方法已编译。更好的方法是使用注释和XML样式的注释对其进行文档化,这对于公共API来说更好。