操作系统:并发执行问题

目录

4.1 并发编程

4.2 进程的互斥与同步

4.2.1  同步与临界段问题


4.1 并发编程

计算任务存在可并行成分

S1和S2两个子任务可并发执行

并发语句:

Parbegin

      S1;

      S2;

   Parend

      S3;

一、并发编程的三种方法

  • 程序员写顺序程序,用自动识别工具识别可并行成分后,组织使用操作系统的进程或线程实现并发。
  • 由程序员识别可并行成分,用并发程序设计语言设计并发程序,由编译系统安排使用进程或线程;
  • 在传统语言基础上,利用操作系统的进程或线程“系统调用”设计并发程序。

二、并发程序设计语言 --- 并发语句

  • 是在传统高级语言基础上增加描述并发的语句。
  • 语法形式

    Parbegin S1;S2; …Sn; Parend;

     Si(i=1,2,…,n) 是单个语句

 Parbegin和Parend之间的语句可以并发执行

三、并发语句描述手段的优缺点

  • 并发语句Parbegin/Parend的结构化特征非常好。
  • 但存在着描述能力不强的缺点,即存在着用Parbegin/Parend语句无法描述的并发优先关系(如下图)。

 四、并发执行机制

  • 实现并发执行,需要通过操作系统支持的进程或线程机制。
  • 操作系统提供进程(线程)创建,结束和同步的系统调用,可直接提供给用户编写并发程序;或由并发语言编译器将并发语言的语句转化为对操作系统的系统调用。

五、与进程相关的系统调用

  • Linux提供了如下系统调用:fork():创建一个新进程。该系统调用执行完成后,系统已创建了一个子进程,该子进程逻辑复制(共享)了父进程的程序,复制了父进程的数据段和栈段。也就是说不管是父进程还是子进程,在被调度后,都从系统调用的返回点开始运行,父进程系统调用的返回值是子进程的进程标识pid;子进程的返回值是0,子进程从trap指令后一条指令开始运行。

  •  –exec类系统调用:改变进程映像,将原有映像作废,用新的执行文件初始化进程映像。该类系统调用有6种不同形式:
    • int execl(const char *path, const char *arg, ...);

      int execlp(const char *file, const char *arg, ...);

      int execle(const char *path, const char *arg, const char *envp[]);

      int execv(const char *path, const char *argv[]);

      int execve(const char *path, const char *argv[], const char *envp[];

      int execvp(const char *file, const char *argv[]);

  • exitstatus):进程结束。该系统调用发出后,操作系统将从系统中删除调用exit的进程。

  • wait&status):等待子进程结束。当有多个子进程时,任一个子进程结束即将控制返回调用者,并将子进程调用exitstatus)时的status值送到&status指针所指单元中。在控制返回调用者时,同时将所等到的子进程pid作为wait()系统调用函数的返回值。

  • waitpidpid):等待pid所指定的进程结束。

六、多进程实现前述的计算任务并发

pid =fork();

if (pid ==0)

{

S2;//如果S2是一段指令放在另外文件中,则用exec类系统调用

exit(0);

}

else

S1;

wait();

S3;

4.2 进程的互斥与同步

  • 同步关系(亦称直接制约关系)指完成同一任务的伙伴进程间,因需要在某位置上协调它们的工作而等待、传递信息所产生的制约关系。
  • 互斥关系(亦称间接制约关系)即进程间因相互竞争使用独占型资源(互斥资源)所产生的制约关系。

4.2.1  同步与临界段问题

1同步问题。如果进程P1执行S1S3,进程P2执行S2,则P1在执行S3之前必须等待P2执行完S2

例2P1P2两进程使用同一打印机。如果不互斥使用会交叉输出

        例3: 存取钱对共享变量count的互斥访问

        例4有限缓冲区的生产者/消费者问题(生产者和消费者共享一个产品缓冲链) 

 

数据结构示意

typedef  struct{

……

} item;   // 消息类型

 typedef  struct{

  struct buffer *next;

  struct item  inst; 

} buffer;   // 缓冲类型

struct buffer   *P,*C,*First;

struct item      nextp,nextc;

First= nil;
Parbegin
    Producer(){
	      do{
	             ...
                 produce an item in nextp;
                 ...

                 new(P);     #获得一空缓冲区
	             P->inst=nextp;
	             P->next=First;
	             First=P;
	   }while(1);
   };
  
  Consumer(){
            do{
	      while (First==nil); //空循环等
	      C=First;
	      First=First->next;
	      nextc=C->inst;
	      dispose(C);  //释放缓冲区

               ...
		       consume the item in nextc;
			   ...
		     }while(1);
	     };
         Parend;

T0consumer        C= First

T1producer         P->next= First

T2producer         First= P

T3consumer        First= First->next

则会发生生产者加入队列的缓冲区丢失,所以应该互斥执行

临界资源(critical resource一次仅允许一个进程使用的资源

临界段(critical section) 相关进程必须互斥执行的程序段

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值