Unix/Linux编程:Xinu中的进程

进程

创建和终止

操作系统提供创建新进程和结束现有进程的机制。Xinu操作中使用create创建一个新进程,它返回一个进程标志号:

procid = create(argument);  // create a new process

如果要结束一个进程,可以调用kill

kill(procid); // terminate a process 

信号量—同步

操作系统必须提供进程之间的相互通信的机制,比如:计数信号量semaphore、端口和消息传递

通常,计数信号量就是通用的进程同步机制。操作系统提供一个函数screate创建信号量,它返回一个信号量标识符,操作标识符必须用到这个信号量标识符

semid = screate(initcount);

每个信号量包含一个计数用的整数,调用者在创建信号量时赋予该整数一个初始值。一旦信号量产生,进程可以使用wait和siggnal系统调用来管理信号量。当进程调用wait时,操作系统对信号量的计数值减1,如果计数值变为负值,则进程被阻塞。当进程调用signal时,操作系统将信号量的计数值加1,如果有任何一个进程因该信号量被阻塞的话,此时这个进程将被重新激活

使用信号量可以提供“互斥机制”。程序员必须为所有受保护的代码提供一个信号量,其初始值为1

s = screate(1);

然后,用wait和signal语句将关键代码围起来:

wait(s);
// critical code
signal(s);

第一个进程执行wait(s)时,将信号量s的计数值减0,并继续执行(由于计算器此刻不为0)。如果进程结束,则执行signal(s),使s的计数值回到1.然而,如果第一个进程正在使用关键代码时,第二个进程调用wait(s),计数器值将变为负值,因此第二个进程将被阻塞。类似,如果此时碰巧还有第三个进程执行wait(s),计数器仍然为负值,则第三个进程也将被阻塞。当第一个进程执行完毕后,它将调用signal(s),给计数器值加1,唤醒第二个进程。第二个进程执行关键代码,此时第三个进程仍然在等待。当第二个进程结束后并执行了signal(s)后,第三个进程才能开始使用关键代码。其中心思想是任何时刻只能有一个进程执行关键代码,所有其他试图执行相同关键代码的进程都将被阻塞

除了提供互斥机制外,还可以利用信号量来保持队列访问的同步。由于队列的容纳有限,因此队列的同步也是必要的。假设一个队列空间也可以容纳N个数据项,由多个并发进程要将它们生成的数据置入该队列中(“生产者”)。与此同时我们假设另一组进程将从队列中提取数据并处理它们(“消费者”)。如果生产的速度比消费的速度快,那么队列最终将被装满。在队列全满的情况下,任何试图插入新元素的生产者必须被阻塞,以等待消费者从队列中取出一个数据项。同样,如果消费者速度更快,那么它可能会将队列中所有数据全部取出,那么此时它必须被阻塞,直到由数据被生成出来。在访问一个长度为N的队列时,需要两个信号量来调度生产者和消费者。这两个信号量初始化如下:

s1 = screate(N);  // counts space in queue
s2 = screate(0);  // counts items in queue

信号量被初始化后,生产者和消费者用他们来协调同步。一个生产者执行如下:

wait(s1); // wait for space
// ... insert item in next available slot...
signal(s2);  // signal item available

消费者执行:

wait(s2);  // wait for item in queue
// ... extract oldest item from queue
signal(s1); // signal space available

信号量保证了当队列全满时生产者进程被阻塞,当队列全空时消费者进程被阻塞。初次之外,生产者和消费者可以正常运行。

进程间通信

端口

在Xinu操作系统中,“端口”(port)这个抽象模型把进程的数据集中传送到一点处理。我们把端口看出是一个有限的消息队列,该消息队列有两个控制访问的信号量。程序调用pcreate函数生成一个端口,其入口参数指定队列的大小。pcreate返回一个端口标识符,用于引用该端口:

portid = pcreate(size); // create a port specifying size

生成一个端口后,进程可以调用psend和preceive来放置和取出端口中的数据项。psend过程向端口发送消息:

psend(portid, message); // send a message to a port

psend需要两个参数:一个端口标识号和一个要发送的单字消息(在TCP/IP中,消息经常是一个指针,执行某一分组)

preceive从端口提取一个消息:

message = preceive(port);

端口自带信号量机制:如果端口全满,则调用psend的进程被阻塞;如果端口全空,则调用preceive的进程被阻塞。一旦某个进程由于调用psend过程而被阻塞,那么它将保持阻塞状态,直到另一个进程调用了preceive为止。反之亦然。

为了使得进程能够判断psend是否会导致阻塞,系统提供了函数pcount,它允许进程检测一个端口是否已满:

n = pcount(portid); // find out whether a port is full

pcount返回该端口现有的数据项技术。如果返回值为0,则端口为空;如果返回值和端口的大小相等,则端口全满

消息传送

进程还可以通过消息传送来实现相互通信以及传送同步。消息传送运行一个进程直接将消息发送给另一个进程。进程通过调用send函数将消息发送给指定进程:

send(msg, pid); // send integer msg to process pid

一个进程调用receive来等待某个消息的到达:

message = receive(); // wait for msg and return it

在系统中,调用receive的进程将比阻塞,直到某个信息到达,而调用send函数的进程总是继续运行。如果在两次连续调用send之间没有进程调用receive函数以接收消息,那么第二次调用send函数时将返回SYSERR,而该消息无法发送。构造一个良好的系统以保证消息不会丢失的工作由程序员完成。为了协助消息交换的同步,程序可以使用函数recvelr,该函数删除所有正在等待被接收的消息,但不阻塞进程:

message = recvclr(); // clear message buffer;

由于大多数协议规定了等待确认的最长时间,因此在程序中经常会使用消息传送函数recetim,该函数是receive的翻版,但它允许调用者指明等待的最长时间。如果消息在此上限时间内到达,recvtim将其返回给调用者。否则,recetim返回一个特定代码TIMEOUT

message = recvtime(50);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值