在同步的基础上,进程被归类为以下两种类型之一:
- 独立进程:一个进程的执行不影响其他进程的执行。
- 合作进程:一个进程的执行会影响其他进程的执行。
在协作进程的情况下出现进程同步问题也是因为资源在协作进程中共享。竞争条件
在这种情况下,当多个进程正在执行相同的代码或访问相同的内存或任何共享变量时,共享变量的输出或值可能是错误的,因此所有进程都在争先恐后地说我的输出是正确的,这种情况称为竞争条件。多个进程同时访问和处理对同一数据的操作,结果取决于访问发生的特定顺序。
竞争条件是可能发生在临界区中的情况。当临界区中多线程执行的结果根据线程执行的顺序不同时,就会发生这种情况。
如果将临界区视为原子指令,则可以避免临界区中的竞争条件。此外,使用锁或原子变量进行适当的线程同步可以防止竞争条件。临界区问题
临界区是一次只能被一个进程访问的代码段。临界区包含需要同步以保持数据变量一致性的共享变量。
在入口部分,进程请求进入临界区。
临界区问题的任何解决方案都必须满足三个要求:
- 互斥:如果进程在其临界区执行,则不允许其他进程在临界区内执行。
- 进度:如果临界区中没有进程正在执行,而其他进程在临界区外等待,那么只有那些未在其剩余部分中执行的进程才能参与决定下一个进入临界区的进程,并且选择可以不会无限期推迟。
- 有界等待:在一个进程发出进入其临界区的请求之后和该请求被授予之前,允许其他进程进入其临界区的次数必须存在一个界限。
彼得森的解决方案
Peterson’s Solution 是一种基于经典软件的临界区问题解决方案。
在 Peterson 的解决方案中,我们有两个共享变量:
- boolean flag[i] : 初始化为 FALSE,最初没有人有兴趣进入临界区
- int turn : 轮到进入临界区的进程。
彼得森的解决方案保留了所有三个条件:
- 互斥是有保障的,因为在任何时候只有一个进程可以访问临界区。
- 进度也有保证,因为临界区外的进程不会阻止其他进程进入临界区。
- 由于每个进程都有公平的机会,因此保留了有界等待。
彼得森解决方案的缺点
- 它涉及忙等待
- 它仅限于 2 个进程。
测试与设置
TestAndSet 是同步问题的硬件解决方案。在 TestAndSet 中,我们有一个共享锁变量,它可以取两个值之一,0 或 1。0 Unlock 1 Lock
在进入临界区之前,一个进程会查询锁。如果它被锁定,它会一直等待直到它变得空闲,如果它没有被锁定,它就会获取锁并执行临界区。
在 TestAndSet 中,保留互斥和进度,但不能保留有界等待。问题: enter_CS() 和 leave_CS() 函数实现进程的临界区是使用 test-and-set 指令实现的,如下所示:
int TestAndSet(int &lock) { int initial = lock; lock = 1; return initial; } void enter_CS(X) { while test-and-set(X) ; } void leave_CS(X) { X = 0; }
在上面的解决方案中,X 是与 CS 关联的内存位置并被初始化为 0。 现在,考虑以下语句:
一、上述CS问题的解决方案是无死锁的
二、解决方案是无饥饿。
三、进程按 FIFO 顺序进入 CS。
四、多个进程可以同时进入CS。以上哪些说法是正确的?
(一)我
(B) II 和 III
(C) II 和 IV
(四)四单击此处获取解决方案。
真的
信号量信号量是一种信号机制,等待信号量的线程可以由另一个线程发出信号。这与互斥体不同,因为互斥体只能由调用等待函数的线程发出信号。
信号量使用两个原子操作,等待和信号进行进程同步。
信号量是一个整数变量,只能通过两个操作wait()和signal() 访问它。
有两种类型的信号量:二进制信号量和计数信号量- 二进制信号量:它们只能是 0 或 1。它们也被称为互斥锁,因为这些锁可以提供互斥。所有进程可以共享同一个初始化为 1 的互斥信号量。然后,一个进程必须等到锁变为 0。然后,该进程可以使互斥信号量 1 并启动其临界区。当它完成它的临界区时,它可以将互斥信号量的值重置为 0,其他一些进程可以进入它的临界区。
- 计数信号量:它们可以具有任何值并且不受特定域的限制。它们可用于控制对同时访问数量有限制的资源的访问。信号量可以初始化为资源的实例数。每当进程想要使用该资源时,它都会检查剩余实例的数量是否大于零,即进程是否有可用的实例。然后,进程可以进入它的临界区,从而将计数信号量的值减 1。在进程使用资源实例结束后,它可以离开临界区,从而使可用实例数加 1资源的。
真的