pthreads programming Chapter 3: Synchronizing Pthreads 翻译

来源:互联网 发布:淘宝运营组织架构 编辑:程序博客网 时间:2024/06/11 00:26

Chapter 3: Synchronizing Pthreads
第三章:同步线程

Overview
概述

Creating threads is the easy part. It's harder to get them to share data properly. We're tempted to make the obvious analogy to children. To prevent damage to the Nintendo (and the children), we'll only let the one who folds the laundry that evening play Donkey Kong. Similarly, to make threads share data safely, we must ensure that threads that would otherwise behave independently access shared data in an orderly and controlled way. This concept is called synchronization.(The other concept is called good parenting.)
创建线程是很简单的,困难的是让线程之间正确的共享数据。为了更好理解,我们做个小孩的类比。为了防止伤害Nintendo(任天堂)(和孩子),我们将只让当晚叠衣服的人玩Donkey Kong(金刚,游戏名)。类似,为了让线程安全的共享数据,我们必须保证相互独立线程以一种有序、可控的方式使用共享数据。这种概念叫做同步(另一种叫法是当好一个父亲)

Sooner or later, you'll probably make a programming error and fail to synchronize threads. It would be nice if you could get a feel for the symptoms of synchronization failures so that you can react quickly and expertly to such a disaster. Unfortunately, as we'll see, almost any type of quirky behavior might be regarded as a symptom of a synchronization failure. Worse, you may see problems only every so often when you run your program; at other times, if the threads in the program just happen to access data in the right order in a particular run, the program may run fine. So you may notice incorrect output at random times perhaps in one run out of a hundred. In fact, this come-and-go quality of errors may be the best indicator that your bug is in the way in which you've handled thread synchronization.
迟早你会犯下同步线程失败的编程错误。所以能了解些线程同步失败后所显现的错误信息是很好的,这能使我们快速有效的修正这些错误。但很不幸,如我们将要看见的,几乎任何诡异的现象都可以认为是同步(错误的)征兆。更糟糕的是,当你运行程序时候,错误偶然的出现了。但多数情况下,如果线程之间正确的访问数据,程序可能会运行的非常好。所以可能程序运行100次中的随机一次,才能让你意识到有错误。事实上,这种忽隐忽现的错误,正是最好的提示,你的bug 是由于线程同步(错误)引起的。

Let's suppose we forgot to include synchronization in the ATM server we created in Chapter 2, Designing Threaded Programs. When one of our imaginary bank's customers deposits money in an account, she expects that, ultimately, her account balance will be its original value plus the amount she deposited. She probably can't even conceive of anything our bank could do to interfere with her transaction and cause her end balance to be any different than she expects. In other words, she assumes that her deposit is a single, indivisible transaction (if she were a software engineer, she'd know that the word for that type of transaction is atomic)that occurs in isolation from other transactions. It's anything but. Her deposit may consist of many, many separate tasks: disk reads, memory reads, calculations, data modifications, memory writes, disk writes, and more. Worse, without synchronization in our ATM server, we'll allow a similar transaction to preempt her deposit at any step before all of the steps required to make it a deposit have completed.
假设,在的第二章 设计线程程序 里写的ATM服务端程序,我们忘记在引入同步操作。想象当一个的银行客户往她的帐户存钱时,她预料她帐户最终的余额将是最初的余额加上这次她存入的钱。她大概不能想象我们银行干扰她正在处理事务,导致她最终的存款余额和她的预期不一致。换句话说,她认为她存款是单个独立的事务(如果她是个软件开发人员,她应该知道对应术语叫原子性),独立于其他的事务。事实并非如此。她的存款(过程)包含了很多独立的工作:读硬盘、读内存、计算、修改数据、写内存、写硬盘等等。糟糕的是,如果在我们的ATM服务端程序里没有同步(机制),在任何阶段,其他的存款事务将抢占当前的存款事务,致使她的不能彻底完成。

But it's likely she'll have no problems until, for instance, she tries to withdraw $50 from her account at the same time her husband across town also tries to withdraw $50. This type of problem is known as a race condition. A race condition is illustrated in Figure 3-1.
但她可能没有什么问题,直到某次她想从她账户中取出50元,同时她老公在镇上的另一端也想取50元。这种情况被描述为竞争条件。图3-1解释了竞争条件




Figure 3-1: ATM race condition with two withdraw threads



In a race condition, two or more threads access the same resource at the same time. In Figure 3-1, Thread 1 and Thread 2 simultaneously attempt a withdrawal from the same bank account. Thread1 reads the current balance of the account—$125. However, before it can proceed with the other steps that complete the withdrawal (the arithmetic, the storing of the new result, and the dispensing of cash), it is preempted by Thread 2. Thread 2 also reads the account balance—$125, but Thread 2 continues on to complete the transaction. It subtracts $50 from$125, stores the new balance, $75, in the account database, and hands the customer a $50 bill. Sometime thereafter, Thread 1 resumes, subtracts $50from $125 (which is what it thinks is the account balance), stores the new balance, $75, in the account database, and hands the other customer a$50 bill. Nothing looks wrong to either thread, but in actuality, we've allowed one thread to clobber the write of another. We've subtracted a total of $100 from $125 and have come up with $75. A bank could lose a lot of money if this was allowed to happen.*
在竞争条件时,多于2个线程同时访问相同的资源。在图3-1,线程1和线程2试图同时从同一个账户中取款。线程1读取了当前账户余额125元。然而,在它想继续完成取款的其他步骤时(计算,保存新的余额,分发现金),它被线程2抢占。线程2同样读取了账户余额125元,但它顺利完成了这个事务。它从125中减去50,保存了新的余额,75元,到账户的数据库中,给了顾客50元。一段时间后,线程1从新开始,从125中减去50(它认为账户余额还是125元),保存了新的余额,75元,到账户数据库中,给了另一个顾客50元。每个线程都不认为有错,但实际,我们允许一个线程影响了另一个线程的写操作。我们从125中减去了100却得到75。如果银行允许这样的事发生,它将损失很多钱。

 
*
Actually, the error just happened to be in the customer's favor because the operations were both withdrawals. If the operations were deposits, the error would be in the bank's favor.
事实上,在取款时,错误有利于顾客。但在存款时,错误有利于银行这边。

The problem with our ATM server is that the three key steps in the withdraw transaction the reading of the balance, the calculation of the new balance, and the storing of the new balance in the account database should be atomic. Either all of the steps are performed together without interruption, or none of them are.
我们ATM服务端程序的问题是取款的3个主要步骤(读取余额,计算新的余额,保存新的余额到数据库中),应该是原子的。要么所有的步骤没有有中断的完成,要么什么不做。