CSC8016_Advanced Programming--CriticalSections

Properties of Concurrent Programs

We can say that a program satisfies a given property if this is something that holds true throughout its execution. Some examples are given below:

Safety
E.g., “nothing bad happens”
f the program continues to run, it never makes wrong actions.

This entails that:
If there are threads accessing a same set of resources, threads shall not generate race conditions while accessing data.

Such property can be ensured via synchronization mechanisms.

Liveness
E.g., “something good eventually happens”
The program has not blocks, and continues to compute something

This entails that:
Synchronization mechanisms shall not prevent the termination of the program: a process cannot wait indefinitively before being able to access a shared resource.

我们可以说,一个程序满足一个给定的属性,如果这是一个在整个执行过程中保持真实的东西。以下是一些例子:

安全
例如,“没有什么不好的事情发生”
如果程序继续运行,它永远不会做出错误的动作。

这意味着:
如果有线程访问同一组资源,则线程在访问数据时不应产生竞争条件。

这样的属性可以通过同步机制来确保。

活跃度
例如,“好事终会发生”
程序没有阻塞,继续计算

这意味着:
同步机制不应阻止程序的终止:进程在能够访问共享资源之前不能无限期地等待。

Mutual Exclusion

We say that a resource is accessed in a mutual exclusive way if, at each instant of time, the resource is accessed by at most one thread

Examples:
Two processes that want to print a document using a shared printer.
Two processes that exchange data via a shared buffer.
Two processes that need to update a shared variable.

Busy Waiting

Thread.yield(); means tell the CPU we don’t need to use it (while we are busy waiting). It could be left out, it is just a hint to the CPU.

Later solutions will try to avoid busy waiting it as much as possible.

All the solutions considered so far use one of the following busy statements for delaying threads
while (…) /* do nothing */
while (…) Thread.yield();

I am busy (I test the while condition) but, as a matter of fact, I do nothing except from the condition to be changed (wait)
Typically, “busy waiting” is only used internally by an operating system
For general purpose programming, it is better to use a hardware mechanism suspending the active process and allowing other processes to run, as busy waiting is inefficient
Thread.yield();意思是告诉CPU我们不需要使用它(当我们忙碌等待时)。它可以被忽略,这只是对CPU的一个提示。

以后的解决办法会尽量避免忙碌的等待吧。

到目前为止考虑的所有解决方案都使用以下忙碌语句之一来延迟线程
而(…)/* 什么都不做 */
而(…)System. out. println();

我很忙碌(我测试while条件),但事实上,除了要改变的条件(等待)之外,我什么也不做。
通常,“忙碌waiting”仅由操作系统内部使用
对于通用编程,最好使用硬件机制挂起活动进程并允许其他进程运行,因为忙碌的等待是低效的

Test & Set

Most CPUs have an atomic test-and-set instruction of the form TS(CPU-register, memory-address, value)

TS is a special hardware instruction performing a test and an assignment as a single atomic operation. It:
retrieves the contents of the given memory-address into the designated CPU-register,
and then stores the specified value into the memory-address

It is possible to implement a boolean function testAndSet(flag) which uses TS, that atomically sets flag to true and returns the previous value of flag

Atomicity guarantees that two threads cannot execute testAndSet simultaneously on the same variable

大多数CPU都有一个TS(CPU寄存器,内存地址,值)形式的原子测试和设置指令。

TS是将测试和赋值作为单个原子操作执行的特殊硬件指令。它:
将给定存储器地址的内容检索到指定的CPU寄存器中,
然后将指定值存储到存储器地址中

可以实现一个使用TS的布尔函数testAndSet(flag),它原子地将flag设置为true并返回flag的前一个值

原子性保证两个线程不能同时对同一个变量执行testAndSet

Test&Set: Locks with AtomicBooleans

public class TASLock implements Lock {
AtomicBoolean state = new AtomicBoolean(false);
public void lock() { while (state.getAndSet(true)) {} }
public void unlock() { state.set(false); }
}

The first thread acquiring the lock reads false and terminates the loop.
A second thread attempting at acquiring the lock will be start waiting indefinitively ( while (true); ).
The second thread will stop waiting as soon as the thread in the critical section will set the value back to false
获取锁的第一个线程读取false并终止循环。
第二个试图获取锁的线程将不确定地开始等待(while(true);)。
第二个线程将停止等待,只要临界区中的线程将该值设置回false

The synchronized keyword

synchronized implements a mutually exclusive lock on a specified resource
In Java, each object comes with an associated and implicit lock
synchronized在指定资源上实现互斥锁
在Java中,每个对象都有一个关联的隐式锁

The synchronized method

synchronized methods are synchronized with respect to this
This prevents interference between simultaneous calls to synchronized methods of the same object
However, it is still possible for unsynchronized code to interfere with synchronized code
Also, synchronized method calls to different objects can execute independently of each other
Synchronized methods can be also expressed via ReentrantLocks by initializing such an object within the object’s constructor, and calling lock at the beginning of the method, and unlock at its end
同步的方法与此同步
这可以防止对同一对象的同步方法的同时调用之间的干扰
但是,非同步代码仍然有可能干扰同步代码
而且,对不同对象的同步方法调用可以彼此独立地执行
同步方法也可以通过ReentrantLocks来表示,方法是在对象的构造函数中初始化这样一个对象,并在方法的开头调用lock,在方法的结尾调用unlock

Example

First, […] when one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block(suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any
subsequent invocation of a synchronized method for the same object.

首先,[…]当一个线程正在为一个对象执行一个同步方法时,所有其他为同一个对象调用同步方法的线程都会阻塞(挂起执行),直到第一个线程完成对该对象的处理。

其次,当synchronized方法退出时,它会自动与任何同一对象的同步方法的后续调用。

public class SynchronizedCounter {
private int c = 0;
public synchronized void increment(){c+
+;}
public synchronized void decrement()
{c–;}
public synchronized int value(){ return
c;}
}

The synchronized statement

Instead of using ReadWriteLocks, for specific variables, we can have coarse grained (e.g., always mutually exclusive) locks over objects by associating a synchronized block to it:
synchronized (object) { /* some code here

Methods of a given class MyClazz can be also declared as synchronized: in this situation, the object that might
invoke such method is the whole “lock”.

If the method is a static one, then the “lock” is MyClazz.class

Recursive locking

What happens if a synchronized method calls another synchronized method on the same object?
Java supports recursive locking-this means that the owner of a lock is allowed to acquire the lock of the same object again
The lock is only released when all of the synchronized method calls have completed
Java支持递归锁–这意味着允许锁的所有者再次获取同一对象的锁

只有当所有的同步方法调用都完成时,锁才会被释放
//this O(n) method increments a value by n
public synchronized void increment(int n) {
if (n>0) {
value = value +1;
increment(n-1);
}
}

Dekker’s and Peterson’s Algorithms

Dekker provided a solution that could be proved logically correct. This solution was reported by Dijkstra in 1965.

Peterson subsequently devised a simpler solution to the problem that is arguably easier to understand

Their solutions depend only on the hardware memory interlock property,namely atomic reads and writes of single memory locations, and the use of volatile variables

In order to illustrate the subtleties of the problem, and motivate Dekker and Peterson’s solutions, we will consider a series of increasingly elaborate incorrect “solutions” that lead towards correct solutions.

Assumption: we have two threads, one with id 0, and the other with id 1.
德克尔提供了一个可以证明逻辑正确的解决方案。Dijkstra在1965年报道了这个解。

彼得森随后设计了一个更简单的解决方案,可以说是更容易理解的问题

他们的解决方案仅依赖于硬件内存互锁属性,即单个内存位置的原子读写,以及volatile变量的使用

为了说明问题的微妙之处,并激发德克尔和彼得森的解决方案,我们将考虑一系列日益复杂的不正确的“解决方案”,导致正确的解决方案。

假设:我们有两个线程,一个id为0,另一个id为1。

  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值