C# 在C语言中同步缓冲区#

C# 在C语言中同步缓冲区#,c#,multithreading,C#,Multithreading,所以我对C#和多线程都是新手。我得到了这个应用程序,它有两个类,writer和reader,它们都引用了我的CharacterBuffer类。因此,我向程序输入一个字符串,编写器应该将chracter读入缓冲区,读取器从缓冲区读取,所有这些都是同步的。这是缓冲区类: public class CharacterBuffer { private static object Lock = new object(); private Queue result; public

所以我对C#和多线程都是新手。我得到了这个应用程序,它有两个类,writer和reader,它们都引用了我的CharacterBuffer类。因此,我向程序输入一个字符串,编写器应该将chracter读入缓冲区,读取器从缓冲区读取,所有这些都是同步的。这是缓冲区类:

public class CharacterBuffer
{
    private  static object Lock = new object();
    private Queue result;

    public CharacterBuffer()
    {
        result = new Queue();
        lock (result);
    }

    public void addChar(char c)
    {
        result.Enqueue(c);
        Monitor.PulseAll(result);
    }

    public char readChar()
    {
        Monitor.Wait(result);
        return (char) result.Dequeue();
    }
}
所以我想我要做的是首先声明队列并锁定它。因此,当读卡器调用readChar()时,它必须等到编写器调用addChar(char c)之后。但是,每当我启动读写器线程时,它都会立即抛出一个异常,即mscorlib.dll中发生的System.Threading.SynchronizationLockException


很明显我做错了什么。我已经搜索了一个答案,似乎代码块调用监视器必须在同一个块中进行所有调用。因为在这种情况下,我的独立线程调用它而不是缓冲区本身。所以问题是,;该怎么办?

您只需按如下方式锁定即可:

public class CharacterBuffer
{
    private  static object Lock = new object();
    private Queue result;

    public CharacterBuffer()
    {
        result = new Queue();

    }

    public void addChar(char c)
    {
        lock(Lock)
        {
          result.Enqueue(c);
          Monitor.PulseAll(result);
        }
    }

    public char readChar()
    {
        lock(Lock)
        {
             return (char) result.Dequeue();
        }
    }
}

lock是一种语法糖,它在{part]中输入关键会话,然后将其留在}(或者如果代码以某种方式退出了块)。

您可以像下面这样简单地锁定:

public class CharacterBuffer
{
    private  static object Lock = new object();
    private Queue result;

    public CharacterBuffer()
    {
        result = new Queue();

    }

    public void addChar(char c)
    {
        lock(Lock)
        {
          result.Enqueue(c);
          Monitor.PulseAll(result);
        }
    }

    public char readChar()
    {
        lock(Lock)
        {
             return (char) result.Dequeue();
        }
    }
}

lock是一种语法糖,它在{part]中输入关键会话,然后将其留在}(或者如果代码以某种方式退出了块)。

如果您担心在多个线程中修改队列,请使用以下代码:

public class CharacterBuffer
{
    private object padlock = new object();
    private Queue result = new Queue();

    public void AddChar(char c)
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            result.Enqueue(c);
        }
    }

    public char ReadChar()
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            return (char) result.Dequeue();
        }
    }
}
如果您愿意实现阻塞队列并发送信号,以便读卡器等待写卡器将某些内容放入队列,请使用以下代码:

public class CharacterBuffer
{
    private object padlock = new object();
    private Queue result = new Queue();

    public void AddChar(char c)
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            result.Enqueue(c);
            if (result.Count == 1)
            {
                // wake up any blocked dequeue
                Monitor.PulseAll(padlock);
            }
        }
    }

    public char ReadChar()
    {
        // lock the padlock so that no two threads tries to read/write at the same time
        lock (padlock)
        {
            // block the thread and wait until there is something in the queue
            while (result.Count == 0)
            {
                Monitor.Wait(padlock);
            }

            return (char) result.Dequeue();
        }
    }
}

如果您担心在多个线程中修改队列,请使用以下代码:

public class CharacterBuffer
{
    private object padlock = new object();
    private Queue result = new Queue();

    public void AddChar(char c)
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            result.Enqueue(c);
        }
    }

    public char ReadChar()
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            return (char) result.Dequeue();
        }
    }
}
如果您愿意实现阻塞队列并发送信号,以便读卡器等待写卡器将某些内容放入队列,请使用以下代码:

public class CharacterBuffer
{
    private object padlock = new object();
    private Queue result = new Queue();

    public void AddChar(char c)
    {
        // lock the padlock so that no two threads try to read/write at the same time
        lock (padlock)
        {
            result.Enqueue(c);
            if (result.Count == 1)
            {
                // wake up any blocked dequeue
                Monitor.PulseAll(padlock);
            }
        }
    }

    public char ReadChar()
    {
        // lock the padlock so that no two threads tries to read/write at the same time
        lock (padlock)
        {
            // block the thread and wait until there is something in the queue
            while (result.Count == 0)
            {
                Monitor.Wait(padlock);
            }

            return (char) result.Dequeue();
        }
    }
}

您正以这种方式实现阻塞队列。在构造函数中,您正在锁定队列本身,这是错误的。当您在监视过程中加入或退出队列(放置字符或移除字符)时,应完成锁定。我会做类似的事情:

public class CharacterBuffer
{
    private  static object Lock = new object();
    private Queue result;

    public CharacterBuffer()
    {
        result = new Queue();
        //lock (result);  <-- this is WRONG
    }

    public void addChar(char c)
    {
        Monitor.Enter(Lock){
                result.Enqueue(c);
        }
        Monitor.Pulse(Lock);
    }

    public char readChar()
    {
        char c;
        Monitor.Wait(result);
        Monitor.Enter(Lock){
            c = (char)result.Deqeueue(); 
        }
        return c;
    }
}
公共类字符缓冲区
{
私有静态对象锁=新对象();
私有队列结果;
公共字符缓冲区()
{
结果=新队列();

//锁定(结果);您以这种方式实现了阻塞队列。在您的构造函数中,您锁定了队列本身,这是错误的。锁定应该在您在监视的同时入队或出队(放入字符或移除字符)时完成。我将执行类似的操作:

public class CharacterBuffer
{
    private  static object Lock = new object();
    private Queue result;

    public CharacterBuffer()
    {
        result = new Queue();
        //lock (result);  <-- this is WRONG
    }

    public void addChar(char c)
    {
        Monitor.Enter(Lock){
                result.Enqueue(c);
        }
        Monitor.Pulse(Lock);
    }

    public char readChar()
    {
        char c;
        Monitor.Wait(result);
        Monitor.Enter(Lock){
            c = (char)result.Deqeueue(); 
        }
        return c;
    }
}
公共类字符缓冲区
{
私有静态对象锁=新对象();
私有队列结果;
公共字符缓冲区()
{
结果=新队列();
//锁定(结果);
所以问题是:该怎么做

使用

var buffer=new BlockingCollection();
//开始读线程
var readTask=Task.Run(()=>
{
尝试
{
//从源读取数据并放入缓冲区
foreach(源中的var数据)
{
buffer.Add(数据);
}
}
最后
{
//发出数据结束的信号
buffer.CompleteAdding();
}
});
//开始写线程
var writeTask=Task.Run(()=>
{
foreach(缓冲区中的字符串数据。GetConsumineumerable())
{
//过程数据
}
});
Task.WaitAll(readTask,writeTask);
不需要手动锁定。只需使用简化编程和防止错误的现代方法即可

所以问题是:该怎么做

使用

var buffer=new BlockingCollection();
//开始读线程
var readTask=Task.Run(()=>
{
尝试
{
//从源读取数据并放入缓冲区
foreach(源中的var数据)
{
buffer.Add(数据);
}
}
最后
{
//发出数据结束的信号
buffer.CompleteAdding();
}
});
//开始写线程
var writeTask=Task.Run(()=>
{
foreach(缓冲区中的字符串数据。GetConsumineumerable())
{
//过程数据
}
});
Task.WaitAll(readTask,writeTask);


不需要手动锁定。只需使用简化编程和防止错误的现代方法。

您可以声明一个锁定对象,然后锁定
结果。
。您的锁定应该处于
lock
状态。您也可以不使用
lock()
correcly.why not
ConcurrentQueue
?从头开始。@vtorola:这正是我在回答(请参阅第二个代码片段)中建议做的,你声明了一个锁对象,然后锁定了
结果
。你的锁应该处于
lock
。你也没有使用
lock()
correcly.why not
ConcurrentQueue
?从头开始。@vtorola:这正是我在回答(参见第二个代码片段)中建议做的,因此在您的第一个代码示例lock(lock)基本上就像切换开关一样工作?我不确定我是否理解;假设writerThread在readerThread之前先调用addChar。然后它不会被阻止吗?我不认为两个线程可以同时调用同一实例的ctor:)@vtortola:这不是调用构造函数两次,而是调用addChar或ReadChar之前构造函数已完成。@SnickeSnapshot:在任何给定的时间内,只有一个线程可以对挂锁对象进行锁定。这确保不会并行调用读/写操作,从而破坏
队列
内部状态,而是按顺序调用它们。@KasparsOzols在这种情况下构造实例之前,如何调用实例方法案例?那么在您的第一个代码示例中,lock(lock)基本上像一个切换开关一样工作?我不确定我是否理解;假设writerThread在readerThread之前首先调用addChar。那么它不会被阻止吗?我不认为两个线程可以同时调用同一实例的ctor:)@vtortola:it