除了"荣誉代码"之外,还有一个区别是使用专用的"锁定对象"并直接锁定数据吗?

Ben*_*jin 6 .net c# multithreading synchronization

我有两个线程:一个提供更新,另一个将它们写入磁盘.只有最新的更新很重要,所以我不需要PC队列.

简而言之:

  • 馈线线程将最新更新丢弃到缓冲区中,然后设置标志以指示新的更新.
  • writer线程检查该标志,如果它指示新内容,则将缓冲的更新写入磁盘并再次禁用该标志.

我目前正在使用专用锁对象来确保没有不一致,我想知道直接锁定标志和缓冲区有什么区别.我唯一知道的是,一个专用的锁对象需要信任,每个想要操纵标志和缓冲区的人都使用锁.

相关代码:

private object cacheStateLock = new object();
string textboxContents;
bool hasNewContents;

private void MainTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
    lock (cacheStateLock)
    {
        textboxContents = MainTextbox.Text;
        hasNewContents = true;
    }
}

private void WriteCache() // running continually in a thread
{
    string toWrite;

    while (true)
    {
        lock (cacheStateLock)
        {
            if (!hasNewContents)
                continue;

            toWrite = textboxContents;
            hasNewContents = false;
        }

        File.WriteAllText(cacheFilePath, toWrite);
    }
}
Run Code Online (Sandbox Code Playgroud)

VMA*_*Atm 0

首先,如果您尝试bool以这种方式使用该标志,您应该将其标记为volatile根本不推荐,但比您的代码更好)。

第二件事要注意的是,lock语句是类方法的语法糖Monitor,因此即使您能够为其提供值类型(顺便说一句,这是一个编译错误),两个不同的线程也会获得自己的版本的旗帜,使lock无用。因此,您必须为statements提供引用类型lock

第三件事是字符串在 中是不可变的C#,因此理论上某些方法可能会存储对字符串的旧引用并lock以错误的方式执行操作。另外,在您的情况下,字符串可能会成为nullfrom MainTextbox.Text,这将在运行时抛出,与private永远不会改变的对象进行比较(您应该将其标记为readonly顺便说一下)。

因此,引入专用的同步对象是将锁定与实际逻辑分离的最简单且自然的方法

至于您的初始代码,它有一个问题,因为MainTextbox_TextChanged可能会覆盖未写下的文本。您可以在此处引入一些额外的同步逻辑或使用一些库。@Aron 建议在Rx这里,我个人更喜欢TPL Dataflow,这并不重要。

您可以添加BroadcastBlock链接到ActionBlock<string>(WriteCache),这将删除方法中的无限循环WriteCache以及lock两个方法中的 :

var broadcast = new BroadcastBlock<string>(s => s);
var consumer = new ActionBlock<string>(s => WriteCache(s));
broadcast.LinkTo(consumer);

// fire and forget
private async void MainTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
    await broadcast.SendAsync(MainTextbox.Text);
}

// running continually in a thread without a loop
private void WriteCache(string toWrite)
{
    File.WriteAllText(cacheFilePath, toWrite);
}
Run Code Online (Sandbox Code Playgroud)