我对使用C#lock
构造的一件事很感兴趣
现在从MSDN中取样,然后经过以下主要问题:
以下示例使用线程和锁。只要存在lock语句,该语句块就是关键部分,并且余额永远不会成为负数。
class Account
{
private Object thisLock = new Object();
int balance;
Random r = new Random();
public Account(int initial)
{
balance = initial;
}
int Withdraw(int amount)
{
// This condition never is true unless the lock statement
// is commented out.
if (balance < 0)
{
throw new Exception("Negative Balance");
}
// Comment out the next line to see the effect of leaving out
// the lock keyword.
lock (thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
}
public void DoTransactions()
{
for (int i = 0; i < 100; i++)
{
Withdraw(r.Next(1, 100));
}
}
}
class Test
{
static void Main()
{
Thread[] threads = new Thread[10];
Account acc = new Account(1000);
for (int i = 0; i < 10; i++)
{
Thread t = new Thread(new ThreadStart(acc.DoTransactions));
threads[i] = t;
}
for (int i = 0; i < 10; i++)
{
threads[i].Start();
}
//block main thread until all other threads have ran to completion.
foreach (var t in threads)
t.Join();
}
}
我不明白为什么使用lock
帐户余额不会减少;它总是以0
余额结束编译。
P.S对不起,我的英语。
答案 0 :(得分:1)
该锁将按本示例中的预期工作,一旦启动多个线程,它们都会尝试从帐户中撤出,这可能会导致功能异常。怎么样?
好吧,想象一下当前余额为40,线程1尝试撤回40,线程2尝试撤回20,如果没有锁,它们都会成功完成,余额为-20,这是不可接受的。 / p>
由于您的实际顾虑,为什么余额没有变为负数?简单:
lock (thisLock)
{
if (balance >= amount)
{
Console.WriteLine("Balance before Withdrawal : " + balance);
Console.WriteLine("Amount to Withdraw : -" + amount);
balance = balance - amount;
Console.WriteLine("Balance after Withdrawal : " + balance);
return amount;
}
else
{
return 0; // transaction rejected
}
}
锁将确保仅当余额中有可用金额时每个线程才会退出,因此条件if (balance >= amount)
与if (balance < 0)
结合使用将确保余额不会为负。
如果您记录每个线程提取的金额,则可以查看详细信息:
Console.WriteLine(Withdraw(r.Next(1, 100)));
您会看到其中的许多将在一段时间后输出0,因为该帐户不再具有余额,因此return 0
会触发。
答案 1 :(得分:0)
您正在生成十个线程,它们几乎同时启动并同时运行。与减量操作相比,Console.WriteLine
调用比较耗时,因此如果没有lock
,则多个线程可以并且将进入由if (balance >= amount)
保护的语句块(因为可能仍然有足够的平衡)到那时)同时,其他任何线程都将要到达并执行balance = balance - amount
语句。
(没有Console.WriteLine
调用,问题是相同的-比赛的可能性可能更低,但是除非关键部分是原子操作,否则仍然需要lock
)。
使用lock
时,不会有两个线程同时进入临界区,因此,如果在输入临界区时余额已经为零,它将安全地分支到{{ 1}}块中显示“交易被拒绝”。
我认为,一旦您意识到这是锁语法的真正目的,您的误解就将得到解决-防止对需要序列化读和/或写访问的资源进行竞争(这里的资源是balance变量) )。从那里开始,下一个挑战是else
关键字documented here
答案 2 :(得分:-1)
我不确定100%,但是我假设MSDN提供的示例以类似于生产者-消费者的模式展示了这一点。如果没有lock
,则多个线程在同一个数据上运行(即balance
变量)可能会无意间出错。 lock
确保在任何给定时间只有一个线程可以读写balance
。