static List<int> sharedCollection = new List<int>();
static readonly Object obj = new Object();
static void Main(string[] args)`enter code here`
{
var writeThread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
lock (obj)
{
Write();
}
}
});
var readThread = new Thread(() =>
{
for (int i = 0; i < 10; i++)
{
lock (obj)
{
Read();
}
}
});
writeThread.Start();
readThread.Start();
Console.ReadLine();
}
static void Read()
{
Console.Write("Current collection state: ");
sharedCollection.ForEach((e) => Console.Write($"{e} "));
Console.WriteLine();
}
static void Write()
{
Random generator = new Random();
var addedValue = generator.Next(1, 20);
sharedCollection.Add(addedValue);
Console.WriteLine($"Added value is: {addedValue}");
}
我花了很多时间试图理解为什么我会收到这个:控制台结果
有人可以向我解释这段代码有什么问题吗?
Mutex 工作正常,但我也需要说明 lock 语句......我希望在每次添加第一个线程后我从第二个线程获得一个集合状态。像这样:
Added value: 1
Collection state: 1
Added value: 15
Collection state: 1 15
Added value: 4
Collection state: 1 15 4
我知道您希望这些线程在某种程度上并行运行,但它们是按顺序执行的。你的期望是正确的。
但是,我认为这与锁定无关。lock 只会阻止读和写同时发生,不会产生这种行为。在没有锁的情况下尝试验证。(但是,由于 JiT Compiler、CPU 缓存失效和优化等因素,如果有锁,即使没有直接影响,结果仍可能有所不同)。
我最好的选择是读取线程太慢了,在写入完成之前它不会完成一次。编写 UI 很昂贵,即使是在像控制台这样微不足道的东西上。或者甚至特别在那里。我使用 robocopy 对用户配置文件进行了大量备份。如果它遇到了很多非常小的文件,那么仅仅编写控制台就会成为实际的程序瓶颈,永远是磁盘访问。突破瓶颈的磁盘访问并不是经常发生的事情。
如果您只为每个用户触发的事件编写一次 UI,您将不会注意到成本。但是从任何形式的循环中执行它 - 特别是在另一个线程中运行的循环 - 你会开始注意到它。我被特别告知,foreach 的执行速度显然是 for 循环的一半。
我什至为此做了一个例子,尽管是在 Windows 窗体环境中:
using System;
using System.Windows.Forms;
namespace UIWriteOverhead
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int[] getNumbers(int upperLimit)
{
int[] ReturnValue = new int[upperLimit];
for (int i = 0; i < ReturnValue.Length; i++)
ReturnValue[i] = i;
return ReturnValue;
}
void printWithBuffer(int[] Values)
{
textBox1.Text = "";
string buffer = "";
foreach (int Number in Values)
buffer += Number.ToString() + Environment.NewLine;
textBox1.Text = buffer;
}
void printDirectly(int[] Values){
textBox1.Text = "";
foreach (int Number in Values)
textBox1.Text += Number.ToString() + Environment.NewLine;
}
private void btnPrintBuffer_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(10000);
MessageBox.Show("Printing with buffer");
printWithBuffer(temp);
MessageBox.Show("Printing done");
}
private void btnPrintDirect_Click(object sender, EventArgs e)
{
MessageBox.Show("Generating Numbers");
int[] temp = getNumbers(1000);
MessageBox.Show("Printing directly");
printDirectly(temp);
MessageBox.Show("Printing done");
}
}
}
但即使是这种开销也不太可能产生持久的结果。有时读线程应该先获得锁,阻塞写。但是,仍然有太多的变数无法确定。你应该尝试一个更简单的例子,更一致(和更少)的写作。将“A”和“B”写入控制台怎么样,而不是像这样复杂的东西?
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句