c# - 如何使类中的属性线程安全

标签 c# .net multithreading console-application

我有一个具有某些功能的控制台应用程序,并且我有一个类执行一些操作,例如向服务发布一些消息。现在,在该类上发布的每条消息上,我都会增加一个计数器。并且我有一个与该计数器关联的委托(delegate),以便在达到限制后,我在 Program.cs 上有一个事件来阻止调用。现在我正在执行异步发布部分。那么如何保护柜台属性(property)。

下面是我的代码:

Program.cs

var objMessageManager = new MessageManager();
objMessageManager.MaximumLimitToStopRequest += objMessageManager_MaximumLimitToStopRequest;

static void objMessageManager_MaximumLimitToStopRequest(object sender, int ItemCount)
{
    if (ItemCount > Settings.MessageLimit)
    {
        Task.Delay(Settings.MessageDelayTime);
    }
}

下面是 MessageManager.cs 类的代码

internal delegate void StopRequestEventHandler(object sender, int ProcessedItem);

public event StopRequestEventHandler MaximumLimitToStopRequest;

private int ProcessedItem;

private int noOfProcessed;

public int NoOfProcessed
{
    get
    {
        return ProcessedItem;
    }
    private set 
    {
        ProcessedItem = value;
        if (MaximumLimitToStopRequest != null)
        {
            MaximumLimitToStopRequest(this, ProcessedItem);
        }
    }
}

这是方法内的代码

internal async void CreateMessage(xyz sMessageObj)
{
    try
    {
        await Task.Run(() =>
        {
            // Code to publish the message
        });

        Interlocked.Increment(ref noOfProcessed);
        NoOfProcessed = noOfProcessed;
    }
    catch (Exception ex)
    {
        Log.Error("Exception occurred .", ex);
    }
}

请忽略变量和全部的命名错误。该应用程序运行良好。我需要帮助以使其对于读取和写入/递增 NoOfProcessed 属性都是线程安全的。

最佳答案

不,您的代码在任何情况下都不是线程安全的。首先,在 StopRequestEventHandler 类中,您没有将 ProcessedItemnoOfProcessed 标记为 volatile 。其次,Interlocked.Increment还不够,你必须使用Interlocked的CAS操作,CompareExchange 。第三,您应该考虑创建一个queue,因为ProcessedItem属性可以作为race-condition的目标。

最简单形式的队列是一个简单的更新值的Array,所以我们有一个数组,以及它上面的currentPosition。之后CAS-Exchange operation您只需独立于其他线程使用基于索引的数组项即可。所以代码将是这样的(这是一个非常直接的实现,你应该尝试编写自己的代码):

int[] processedItems = new int[INITIAL_SIZE];
int currentItem = 0;

var current = currentItem;
// make first attempt...
if (Interlocked.CompareExchange(ref currentItem, current + 1, current) != current)
{
    // if we fail, go into a spin wait, spin, and try again until succeed
    var spinner = new SpinWait();
    do
    {
        spinner.SpinOnce();
        current = currentItem;
    }
    while (Interlocked.CompareExchange(ref currentItem, current + 1, current) != current);
}
// store the value in array
processedItems[current] = value

关于c# - 如何使类中的属性线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32143525/

相关文章:

C# 枚举 - 根据掩码检查标志

.net - OPC HRESULT E_FAIL 当连接到远程服务器时

java - 多线程:同步方法的错误行为

java - 在一个线程中创建数据库实体并尝试在另一个线程中检索相同的实体给出不同的结果

python - Twisted:延迟重复触发?

c# - 对象引用未设置为对象 #2 的实例

Java 到 C# 格式说明符

c# - 托管和非托管代码、内存和大小有什么区别?

c# - 如何在 ASP.NET 图表控件中显示值

java - 将 C# RSACryptoServiceProvider 代码翻译成 Java