我从来没有真正写过多线程应用程序。
在我写过的几次中,在我看来,线程安全变得太笨拙太快了。
互联网上到处都是关于线程安全通用技术的教程,但我发现的关于现实世界编程问题的内容并不多。
例如,采用这个简单的代码,(没有任何用处)
StringBuilder sb = new StringBuilder();
void Something()
{
sb.AppendLine("Numbers!");
int oldLength = sb.Length;
int i = 0;
while (sb.Length < 500 + oldLength)
{
sb.Append((++i).ToString());
//something slow
Thread.Sleep(1000);
if (i % 2 == 0)
{
sb.Append("!");
}
sb.AppendLine();
}
}
现在假设我想从多个线程运行这个方法,所有线程都写入同一个字符串生成器。
我希望他们一起写入同一个目标,因此可能会有一个线程中的一行,紧随其后的是另一个线程的另一行,然后下一行从第一个线程返回。
为了对话,我们假设即使在另一行的中间有一行来自一个线程也是可以的
这是代码:
StringBuilder sb = new StringBuilder();
object sbLocker = new object();
void SomethingSafe()
{
int oldLength;
int length;
lock (sbLocker)
{
sb.AppendLine("Numbers!");
oldLength = sb.Length;
length = oldLength;
}
int i = 0;
while (length < 500 + oldLength)
{
lock (sbLocker)
sb.Append((++i).ToString());
//something slow
Thread.Sleep(1000);
if (i % 2 == 0)
{
lock (sbLocker)
sb.Append("(EVEN)");
}
lock (sbLocker)
{
sb.AppendLine();
length = sb.Length;
}
}
}
好累好难读。。。
有没有办法告诉编译器每次可以访问 sb 时都简单地锁定 sbLocker?
为什么我的代码对于这么简单的规则需要如此笨拙?对这种具体但非常有用的技术没有太多思考。可以更容易地完成吗?
我们甚至不能继承 StringBuilder 因为它是密封的。
当然,一个人可以继续包装整个课程:
public class SafeStringBuilder
{
private StringBuilder sb = new StringBuilder();
object locker = new object();
public void Append(string s)
{
lock (locker)
{
sb.Append(s);
}
}
//................
}
但这太疯狂了……因为我们正在使用很多不同的类。
知道如何在这个意义上进行线程安全实践吗?
我知道要创建完全相同的结果,可能有一个更简单的解决方案......但这只是一个例子。我很确定我遇到过类似的问题,但没有任何可读的解决方案。