C# 在C语言中同步缓冲区#
所以我对C#和多线程都是新手。我得到了这个应用程序,它有两个类,writer和reader,它们都引用了我的CharacterBuffer类。因此,我向程序输入一个字符串,编写器应该将chracter读入缓冲区,读取器从缓冲区读取,所有这些都是同步的。这是缓冲区类:C# 在C语言中同步缓冲区#,c#,multithreading,C#,Multithreading,所以我对C#和多线程都是新手。我得到了这个应用程序,它有两个类,writer和reader,它们都引用了我的CharacterBuffer类。因此,我向程序输入一个字符串,编写器应该将chracter读入缓冲区,读取器从缓冲区读取,所有这些都是同步的。这是缓冲区类: public class CharacterBuffer { private static object Lock = new object(); private Queue result; public
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 notConcurrentQueue
?从头开始。@vtorola:这正是我在回答(请参阅第二个代码片段)中建议做的,你声明了一个锁对象,然后锁定了结果
。你的锁应该处于lock
。你也没有使用lock()
correcly.why notConcurrentQueue
?从头开始。@vtorola:这正是我在回答(参见第二个代码片段)中建议做的,因此在您的第一个代码示例lock(lock)基本上就像切换开关一样工作?我不确定我是否理解;假设writerThread在readerThread之前先调用addChar。然后它不会被阻止吗?我不认为两个线程可以同时调用同一实例的ctor:)@vtortola:这不是调用构造函数两次,而是调用addChar或ReadChar之前构造函数已完成。@SnickeSnapshot:在任何给定的时间内,只有一个线程可以对挂锁对象进行锁定。这确保不会并行调用读/写操作,从而破坏队列内部状态,而是按顺序调用它们。@KasparsOzols在这种情况下构造实例之前,如何调用实例方法案例?那么在您的第一个代码示例中,lock(lock)基本上像一个切换开关一样工作?我不确定我是否理解;假设writerThread在readerThread之前首先调用addChar。那么它不会被阻止吗?我不认为两个线程可以同时调用同一实例的ctor:)@vtortola:it