进程同步互斥1

合集下载

实验、进程的同步与互斥——生产者消费者

实验、进程的同步与互斥——生产者消费者

实验、进程的同步与互斥——⽣产者消费者1. 1. 实验⽬的两个或两个以上的进程,不能同时进⼊关于同⼀组共享变量的临界区域,否则可能发⽣与时间有关的错误,这种现象被称作进程互斥。

对CPU的速度和数⽬不做出任何假设的前提下,并发进程互斥访问临界资源,是⼀个较好的解决⽅案。

另外,还需要解决异步环境下的进程同步问题。

所谓异步环境是指:相互合作的⼀组并发进程,其中每⼀个进程都以各⾃独⽴的、不可预知的速度向前推进;但它们⼜需要密切合作,以实现⼀个共同的任务,即彼此“知道”相互的存在和作⽤。

实验⽬的:分析进程争⽤资源的现象,学习解决进程同步与互斥的⽅法。

本实验属于设计型实验,实验者可根据⾃⾝情况选⽤合适的开发环境和程序架构。

1. 2. 实验原理信号量的PV操作与处理相关,P表⽰通过的意思,V表⽰释放的意思。

1962年,狄克斯特拉离开数学中⼼进⼊位于荷兰南部的艾恩德霍芬技术⼤学(Eindhoven Technical University)任数学教授。

在这⾥,他参加了X8计算机的开发,设计与实现了具有多道程序运⾏能⼒的操作系统——THE Multiprogramming System。

THE是艾恩德霍芬技术⼤学的荷兰⽂Tchnische Hoogeschool Eindhov –en的词头缩写。

狄克斯特拉在THE这个系统中所提出的⼀系统⽅法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样⼀些重要的思想和概念都是狄克斯特拉在THE中⾸先提出并为以后的操作系统如UNIX等所采⽤的。

为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运⾏”(running)和“阻塞”(blocking)三个⼯作状态。

由于在任⼀时刻最多只有⼀个进程可以使⽤处理机,正占⽤着处理机的进程称为“运⾏”进程。

当某进程已具备了使⽤处理机的条件,⽽当前⼜没有处理机供其使⽤,则使该进程处于“就绪”状态。

操作系统第6章 进程互斥与同步

操作系统第6章 进程互斥与同步

Co-begin void Producer_i( ) (i=1,2…k) { item next_p; while(1){ produce an item in next_p P(empty); P(s); add next_p to buffer V(s); V(full); } } void consumer_j( ) (j=1,2…m) { item next_c; while(1){ P(full); P(s); remove an item from buffer to next_c V(s); V(empty); consume the item in next_c}} Co-end
• 进入临界段之前要申请,获得批准方可进入; • 退出临界段之后要声明,以便其他进程进入。
用程序描述: While(1){ entry_section; critical_section; exit_section; remainder_section; }
解决临界段问题的软件算法必须遵循:
准则1:不能虚设硬件指令或假设处理机数目。 准则2:不能假设n个进程的相对速度。 准则3:当一个进程未处于其临界段时,不应阻止 其他进程进入临界段。 准则4:当若干进程欲进入临界段时,应在有限时 间内选出一个进程进入其临界段。 用准则3,4不难推出下面原则 协调各进程入临界段的调度原则: • 当无进程处于临界段时,允许一个进程立即进入临界段。
3.实现临界段的硬件方法
利用处理机提供的特殊指令实现临界区加锁。 常见硬件指令有: ⑴ “Test_and_Set”指令 该指令功能描述为: int *target ( 限定为0,1) int Test_and_Set (int *target) { int temp; temp = *target ; *target = 1; return temp; }

解释一下进程同步和互斥的概念,并提供一些实际应用的例子。

解释一下进程同步和互斥的概念,并提供一些实际应用的例子。

解释一下进程同步和互斥的概念,并提供一些实际应用的例子。

解释进程同步和互斥的概念,并提供实际应用例子进程同步和互斥是操作系统中重要的概念,用于确保并发执行的进程能够正确地共享资源和避免竞争条件的发生。

以下是对这两个概念的解释以及一些实际应用的例子:进程同步的概念进程同步是指多个进程在执行过程中按照一定的顺序和规则进行协调以达到预期的结果。

在并行执行的环境下,进程可能会相互依赖或者依赖于某些共享资源,因此需要通过某种机制来保证进程之间的协调与同步。

常见的进程同步机制有:1. 互斥锁(Mutex):一种二进制信号量,用于确保在某一时刻只有一个进程访问共享资源,其他进程需要等待。

2. 信号量(Semaphore):用于控制多个进程对共享资源的访问,可以通过增减信号量的值来实现协调。

3. 条件变量(Condition Variable):用于在某一进程等待某个条件满足时暂停执行,直到条件满足后继续执行。

进程互斥的概念进程互斥是指多个进程对于共享资源的访问被限制为互斥的,即同一时刻只能有一个进程访问共享资源。

这样可以防止并发时的竞争状况,确保每个进程得到正确的结果。

实际应用例子:1. 银行账户:多个用户同时进行转账或查询操作时,需要对账户进行同步操作,避免出现数据不一致的情况。

2. 打印机:多个进程同时请求打印机,需要通过互斥机制来控制打印机资源的访问顺序,避免打印内容交叉或重叠。

3. 多线程编程:在多线程编程中,多个线程共享同一数据结构时,需要使用锁或信号量等机制来保证线程之间的同步和互斥。

这些例子中,进程同步和互斥机制的应用确保了资源的正确使用和并发操作的有序性,提高了系统的稳定性和可靠性。

以上是关于进程同步和互斥的概念解释以及实际应用例子的内容。

进程同步和互斥在操作系统中扮演重要角色,对于确保并发操作的正确性至关重要。

操作系统同步和互斥

操作系统同步和互斥

操作系统同步和互斥操作系统中的进程之间的关系只有两种:同步与互斥。

下面由店铺为大家整理了操作系统的同步和互斥的相关知识,希望对大家有帮助!操作系统同步和互斥1.进程同步进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。

进程间的直接制约关系来源于他们之间的合作。

比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。

而当进程A产生信息放入缓冲区时,进程B才会被唤醒。

2.进程互斥进程互斥是进程之间的间接制约关系。

当一个进程进入临界区使用临界资源时,另一个进程必须等待。

只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。

比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。

扩展:临界资源在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。

但对于某些资源来说,其在同一时间只能被一个进程所占用。

这些一次只能被一个进程所占用的资源就是所谓的临界资源。

典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。

对于临界资源的访问,必须是互诉进行。

也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。

而进程内访问临界资源的代码被成为临界区。

对于临界区的访问过程分为四个部分:1.进入区:查看临界区是否可访问,如果可以访问,则转到步骤二,否则进程会被阻塞2.临界区:在临界区做操作3.退出区:清除临界区被占用的标志4.剩余区:进程与临界区不相关部分的代码临界资源使用规则:忙则等待、优先等待、空闲让进、让权等待(在临界区的进程,不能在临界区内长时间处于事件等待,必须在一定时间退出临界区)。

进程间同步的几种方法

进程间同步的几种方法

进程间同步的几种方法进程间同步是指两个或多个进程之间进行协调,以确保它们能够正确地执行。

这是多任务操作系统中的重要问题,因为进程之间共享资源,包括内存、文件和网络连接等。

进程同步的关键是确保一组进程在处理共享资源时,能够避免发生竞态条件(Race Condition)和死锁(Deadlock)。

竞态条件指多个进程同时访问共享资源,导致不正确的结果。

死锁指多个进程互相等待,导致它们都无法继续执行。

1. 互斥锁互斥锁是最常见的同步方法之一,它被用来保护共享资源,确保同一时刻只有一个进程可以访问它。

当一个进程获取了锁,其他进程必须等待,直到锁被释放。

在 POSIX 系统中,互斥锁可以通过 pthread_mutex_t 数据类型实现。

我们可以使用pthread_mutex_init() 函数初始化锁,使用 pthread_mutex_lock() 函数获取锁,使用pthread_mutex_unlock() 函数释放锁。

下面是一个例子,展示了如何使用互斥锁同步两个进程对共享变量的访问:```c#include <pthread.h>#include <stdio.h>int count = 0;pthread_mutex_t lock;void *increment(void *arg) {for (int i = 0; i < 1000000; i++) {pthread_mutex_lock(&lock); // 获取锁count++;pthread_mutex_unlock(&lock); // 释放锁}return NULL;}在上面的例子中,我们创建了两个线程,它们分别对共享变量 count 进行了一百万次的递增操作。

我们使用了互斥锁来保护 count 变量,确保同一时刻只有一个线程可以访问它。

2. 信号量3. 条件变量条件变量可以被用来支持更高级的同步机制,如互斥锁和信号量。

进程同步机制应遵循的原则

进程同步机制应遵循的原则

进程同步机制应遵循的原则进程同步是指在多个进程之间共享和访问共享资源时,保证数据的一致性和正确性的一种机制。

进程同步机制应遵循以下原则:1.互斥原则:同一时刻只允许一个进程访问共享资源。

互斥可以通过各种技术实现,如信号量、互斥锁等。

通过互斥机制,保证每个进程在执行临界区代码时不会被其他进程干扰,从而保证共享资源的正确性。

2.有限等待原则:进程请求临界资源时,如果该资源被其他进程占用,请求进程应该在合理的时间内得到满足,而不是无限等待。

有限等待原则的目的是避免进程饥饿,确保资源能够公平地被进程使用。

3.活锁避免原则:进程同步机制应该尽量避免活锁的发生。

活锁是指进程在等待资源时不断重试,从而导致系统资源浪费,进程无法继续执行的情况。

为避免活锁,可以引入随机因素或者优先级机制,使得等待资源的进程能够有一定的机会得到资源。

4.顺序访问原则:对共享资源的访问应该按照一定的顺序进行,以避免产生竞争条件。

顺序访问原则可以通过引入排序标记、优先级调度等机制来实现。

5.无饥饿原则:每个进程在请求共享资源时应该能够得到满足,而不是一直被其他进程抢先。

为避免进程饥饿,可以采用公平调度策略,如循环等待。

6.死锁避免原则:进程同步机制应该尽量避免死锁的发生。

死锁是指多个进程因为互相等待对方释放资源而无法继续执行的情况。

为避免死锁,可以采用资源预分配或者资源有序性原则来保证进程不会陷入死锁状态。

7.公平性原则:进程同步机制应该尽量保证每个进程具有公平的获取共享资源的机会。

公平性原则可以通过轮询、随机分配等方法来实现,确保每个进程在请求资源时都有一定的机会得到满足。

以上是进程同步机制应遵循的基本原则,通过遵循这些原则,可以确保多进程之间共享资源时,数据的一致性和正确性,避免竞争条件、死锁、饥饿等问题的发生,保证系统的稳定和可靠性。

第4章 进程的同步与互斥

第4章 进程的同步与互斥

mxh
同步
生产者活动:
Repeat 加工一件物品
消费者活动:
Repeat wait(full)
wait(empty)
物品放入箱中 signal(full)
箱中取一物品
signal(empty) 消耗这件物品
Until false
Until false
mxh
互斥
生产者活动:
Repeat
认为缓冲区同一时刻只有一个人可
mxh
4.1 进程的同步和互斥

信号量定义(记录型信号量)

semaphore是一个结构体: typedef struct {
int value;
//资源的个数
//进程链表
struct process *L;
} semaphore;
mxh
4.1 进程的同步和互斥 申请一个
• 信号量操作wait现在可按如 下来定义: void wait (semaphore S) { S.value - -; if (S.value <0) { add this process to S.L; block(); } }
mxh
4.1 进程的同步和互斥
• 信号量的应用
–合作进程的执行次序 –共享缓冲区的进程的同步
mxh
4.1 进程的同步和互斥
• 合作进程的执行次序:
–保证一组合作进程按照逻辑需要所确定 的次序进行。
mxh
4.1 进程的同步和互斥
• 合作进程的执行次序
–可以用一个图来表示进程集合的执行次 序。图的连接描述了进程开始和结束的 次序约束,此图称为进程流图. –例如P78,图4-2。 –使用信号量机制实现图4-2的同步。(练 习)

进程同步与互斥应用例子

进程同步与互斥应用例子

数据库
写者 { 写数据库; }
读者 { 读数据库; }
进程的互斥
分析:写进程writer、读进程reader因竞争数据库这个资源
而成为互斥关系。因为写进程执行时,不能执行其他读写 进程,所以还必须设置一个计数器统计读进程的个数。如 果是第一个读进程,就与写进程竞争数据库。如果是最后 一个读进程,就释放数据库。因计数器是一个临界资源, 所以多个读进程对计数器的操作又是互斥操作。
进程的同步
解:这是一个同步问题,信号量初值:S2=0,S3=0,S4=0, S5=0,S6=0
进程P1 执行P1 V(S2) V(S3) 进程P4 P(S4) 执行P4 V(S6) 进程P2 P(S2) 执行P2 V(S4) 进程P5 P(S5) 执行P5 V(S6) 进程P3 P(S3) 执行P3 V(S5) 进程P6 P(S6) P(S6) 执行P6
进程的同步
• 例1:假设有三个并发进程P,Q,R,其中P负责从输入设 备上读入信息并传送给Q,Q将信息加工后传送给R,R则负 责将信息打印输出。进程P、Q共享一个缓冲区,进程Q、R 共享另一个缓冲区。
3个进程P、Q、R P进程: 从输入设备上读入信息 将信息放入缓冲区1 Q进程: 从缓冲区1取出信息 将信息放入缓冲区2中 R进程: 从缓冲区2取出信息 将信息打印输出
进程的互斥
练习:过十字路口(单道)。
P4
P1
P3
P2
P1 { 通过路口; }
P2 { 通过路口; }
P3 { 通过路口; }
P4
{ 通过路口; }
进程的互斥
分析:进程P1、P2、P3、P4因竞争十字路口这个资源而成 为互斥关系。 设:信号量m表示十字路口资源,初值为1表示资源可用。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

进程的同步互斥实验
实验目的
1、进一步认识并发执行的实质
2、分析进程竞争资源的现象,学习解决进程同步互斥的方法
实验内容
1、编写程序,使用相关函数实现父子进程对共享文件的同步互斥访问。

2、修改程序,观察对临界资源访问的互斥控制的作用。

实验基础
一、临界资源的互斥访问
为了实现多进程对临界资源的互斥访问,一个进程访问临界资源的典型程序段类似如下形式:
{ ……….
进入区
临界区;
退出区
其余代码;
………}
其中,进入区中判断资源是否可用,如果可用,则资源数量减1,进程进入临界区;否则进程阻塞等待。

退出区中资源数量加1,唤醒阻塞等待该资源的进程。

进入区和退出区都是原子操作。

操作系统中,通常用信号量来实现进入区和退出区,即P操作和V操作。

为了实现用户程序中对某些资源的同步互斥访问,操作系统也提供了一些函数接口,功能类似于对特定临界区的进入区和退出区功能。

二、相关的系统调用
(1)lockf(files,function,size) :用作锁定文件的某些段或者整个文件。

函数原型:
#include <unistd.h>
int lockf(int files,int function;long size)
其中:files是文件描述符;参数function可以取以下值:F_LOCK:锁定一个区域。

F_ULOCK:解除锁定。

参数size指明了从文件当前位置开始的一段连续锁定区域的长度,当size为0时,锁定记录将由当前位置一直扩展到文件尾。

如果lockf的参数function取值为F_LOCK,而指定文件的对应区域已被其他进程锁定,
那么lockf的调用进程将被阻塞直到该区域解锁。

通过使用lockf函数,可实现多进程对共享文件进行互斥访问。

进程的实现中,必须使得每个进程在使用文件前对文件加锁,使用文件后解锁。

(2)open:打开一个文件
函数原型:#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(char *path,int flags,mode_t mode);
其中:参数path 是指向所要打开的文件的路径名指针。

参数falgs 规定如何打开该文件,它必须包含以下值之一:O_RDONL Y,只读打开;O_WRONL Y,只写打开;O_RDWR,读/写打开;O_CREAT,当文件不存在时创建文件,需参数mode;O_APPEND,不论当前文件位置在何处,将文件指针移至文件尾,为write添加数据到文件;O_TRUNC,当以可写的方式成功打开普通文件时,截断该文件的长度为0。

参数mode 规定对该文件的访问权限。

open系统调用可以只使用前面介绍的这两个参数,省略第三个参数mode。

第三个参数是在用O_CREAT创建文件时使用,指出新建文件的存取许可权。

由这个参数指出的存取许可权还要和umask进行运算后才得到新建文件的真正存取许可权。

该运算是由umask按位取反,再按位与上第三个参数给出的数取或(~umask&mode)。

例如:umask为022,mode为0770,则新建文件的存取许可权为0750即-rwxr-x---。

(3)read:读文件
函数原型:#include <unistd.h>
int read(int fd,void *buf,size_t nbytes)
该系统调用从文件描述符fd所代表的文件中读取nbytes 个字节,到buf指定的缓冲区内。

所读取的内容从当前的读/写指针所指示的位置开始,这个位置由相应的打开文件描述中的偏移值(off_set)给出,调用成功后文件读写指针增加实际读取的字节数。

使用read 系统调用时,应注意设置的数据缓冲区充分大,能够存放所要求的数据字节,因为内核只复制数据,不进行检查。

返回:-1:错误;0:文件偏移值是在文件结束处;整数:从该文件复制到规定的缓冲区中的字节数。

通常这个字节数与所请求的字节数相同。

除非请求的字节数超过剩余的字节数,这时将返回一个小于请求的字节数的数字。

(4)write:写文件
函数原型:#include <unistd.h>
int write(int fd,void *buf,size_t nbytes) 该调用从buf所指的缓冲区中将nbytes 个字节写到描述符fd所指的文件中。

(5)lseek:定位一个已打开文件。

函数原型:#include <unistd.h>
int lseek(int fildes,off_t offset,int whence);
系统调用根据whence指定的位置将文件描述符fildes指向文件的文件指针偏移offset
长度的字节数。

Whence的取值及其含义如下:
·SEEK_SET:从文件头开始计算偏移量,文件指针值就是offset的值。

·SEEK_CUR:从文件指针的当前位置开始计算偏移量,文件指针值是当前指针的值加上offset的值。

·SEEK_END:从文件末尾开始计算偏移量,文件指针的值是文件长度加上offset的值,一般可能使用负的偏移量,使得文件指针从后向前移动。

当lseek调用成功时,返回值为一个字节为单位从文件头开始计算文件偏移量的值。

调用失败时,返回值为-1。

文件指针又称文件读/写指针。

文件刚打开时,文件指针指向开头位置;文件读写都是从文件指针处开始,并且在读写过程中同时移动文件指针。

Lseek函数就是用于设置文件指针位置。

(6)close:关闭文件
函数原型:#include <unistd.h> int close(int fd);
每打开一个文件,系统就给文件分配一个文件描述符,同时为打开文件描述符的引用计数加1。

Linux文件系统最多可以分配255个文件描述符。

当调用close()时,打开文件描述符的引用计数值减1,最后一次对close()的调用将使应用计数值为零。

虽然当一个进程结束时,任何打开的文件将自动关闭,明显地关闭任何打开的文件是良好的程序设计习惯。

实验指导
1、观察多进程对共享文件的写入情况。

编写程序:打开共享文件,由父进程创建两个子进程(3个进程并发执行),父进程和两个子进程分别连续向共享文件中写入多行字符串。

多次运行程序,或更改写入行数(或借助sleep函数增加写入时间),观察分析共享文件的写入结果。

2、观察多进程通过共享文件进行通信或合作情况。

编写程序:打开共享文件,由父进程创建一个子进程,父进程从外界获取字符串,并将其写入共享文件;子进程从共享文件中获取字符串,并将其输出出来。

多次运行程序,观察分析进程运行结果。

3、在上述1、2实验程序基础上,用lock/unlock系统调用实现对共享文件的同步互斥访问,多次运行程序,观察分析运行结果。

参考程序
参考程序1
#include<fcntl.h>
#include<stdio.h>
int fatal (const char* info)
{
perror (info);
exit (1);
}
int lock(int fd)
{
lseek(fd,0,SEEK_SET);
if(lockf(fd,F_LOCK,0)==-1)
fatal("lockf()");
return 0;
}
int unlock(int fd)
{
lseek(fd,0,SEEK_SET);
if(lockf(fd,F_ULOCK,0)==-1)
fatal("unlockf()");
return 0;
}
int main()
{
int fd;
int p1,p2,i;
char str[20];
if((fd=open("locked_file.txt",O_RDWR|O_APPEND|O_CREAT,0666))<0) fatal("open");
write(fd,"=========\n",10);
while((p1=fork( ))== -1); /*创建子进程p1*/
if (p1==0)
{
lock(fd); /*加锁*/
for(i=0;i<3;i++)
{
sprintf(str,"daughter %d\n",i); write(fd,str,strlen(str));
sleep(1);
}
unlock(fd); /*解锁*/
}
else
{
lock(fd); /*加锁*/
for(i=0;i<3;i++)
{
sprintf(str,"parent %d\n",i);
write(fd,str,strlen(str));
sleep(1);
}
unlock(fd); /*解锁*/ wait(NULL);
}
close(fd);
}。

相关文档
最新文档