设为首页 加入收藏

TOP

基于toyix的进程和轻权进程的学习(三)
2017-01-02 08:15:12 】 浏览:894
Tags:基于 toyix 进程 学习
撤销,而是继续执行。这说明
exec创建的不是轻权进程。


那么如果exec函数在主进程中,能够用新创建的进程覆盖主进程吗?我们将程序1修改为如下:



执行结果为:



可见exec并没有创建执行新的进程,主进程也没有被覆盖。查看函数手册发现exec如果执行失败了exec会返回-1.printf函数打印exec的值,发现果然是-1



那么就说明exec执行失败了,为什么它会执行失败呢?因为现在主进程如果被覆盖,那么它的数据段就会释放,但是此时轻权进程还要继续使用这个数据段,会发生错误,所以主进程无法被覆盖。要使exec能够执行成功,第一可以使轻权进程在主进程被覆盖前就执行完毕,第二可以使轻权进程通过exec升级成为一个普通进程,第三可以使用fork来创建子进程。我们修改程序,用getch()使主进程等待直到轻权进程执行完毕。



执行结果如下:



果然,轻权进程结束后,主进程执行exec成功创建新进程覆盖了主进程。


do11将上面的程序执行两个进程,结果过如下:



发现在这个过程中当打印第一行a的时候进程监视器显示进程1在执行,进程2是就绪态,但是当第一行a输出完了显示的还是进程1在执行,进程2没有了。那么难道第一行a是进程2创建的新进程输出的?,但是这个过程中进程1才是处在执行态。我们来分析一下过程:首先进程12的轻权进程都执行完,进程1getch()收到了输入的消息,执行exec创建一个新的进程覆盖原来的进程1,这个新的进程的进程号就是1,然后它执行输出,执行完毕后结束,这时就只有处于就绪态的进程2了,进程2执行exec创建一个新的进程,因为之前的进程1不存在了,所以这一个新的进程的进程号就是1,所以我们才会看到进程1一直处于执行态。



我们可以用forkfrkcobegin函数创建多个进程并使它们并发执行,进程的执行需要一些资源,那么当多个进程并发执行时要使用相同的资源怎么办?我们把一个全局变量当作资源,设计两个进程都对这个全局变量进行操作:



执行结果如下:



如果这两个进程并发执行的话,第一个进程先使用资源,对a1并输出,那么先输出的应该是a=1,第二个进程输出的是a=2。为什么这两个进程输出的都是a=2呢?因为f1中有延时函数delay50),在f1延时时f2的进程对a加了1,所以f1输出a的时候a的值已经变成了2.也就是说f1f2的进程并发执行有可能导致f1f2的公共资源使用出错。那么怎么解决这个问题呢?要得到正确的结果,就要让一个进程的执行过程中不会被其他进程所干扰,形成进程互斥。即让一个进程的执行内容像一个原子操作,具有原子性。


我们可以使用PV原语来保证进程的原子性,PV原语是对于信号量的操作,信号量的值代表有几个资源,P操作是将信号量减1,如果执行后信号量大于等于0,就继续执行,否则将该进程堵塞并置于该信号量的阻塞队列中。V操作是对信号量加1,如果执行后信号量的值大于0,那么就将继续执行,否则从该信号量的等待队列中唤醒一个等待的进程。也就是说,P操作是将当前进程由运行态转为阻塞态,而V操作是将一个阻塞态的进程转成就绪态。而他们对进程的阻塞和唤醒是根据当前信号量的值来判断的,因为号量的值就代表了当前资源的数目。


我们使用PV操作来对上面的程序进行修改:




执行结果为:



执行结果是正确的。我们先将信号量的值设置为1,然后将f1f2并发执行,这时如果f1先执行,执行p操作,s=0,进程继续执行,此时如果执行进程2,执行p操作,s=-1<0,进程就会被阻塞放入等待队列中,f1的进程就会继续执行,当执行到v操作,s=0,不符合执行条件,则唤醒等待队列中的f2的进程,当f2v操作执行完,这时s=1可以通过,则进程执行完成。所以在f1进程执行过过程中,不管有多少进程执行了,都会被转到阻塞态,s可能会很小,但是在当前进程执行v操作时会不停唤醒等待队列中的进程直到s大于0,所以在当前进程执行时不会有其他的进程来执行,这样就实现了进程的互斥性。


这里我们所说的进程间的通信,指的就是进程能够一个一个来执行,不会“抢”,通过信号量还有PV操作,我们实现了进程的互斥性,就是进程间像是能够通信一样,当一个进程运行时,其他进程全部阻塞。



生产者-消费者问题也称有限缓冲问题,是一个多线程同步的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的生产者消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。


生产者、消费者问题有几种形式,我们来分别讨论:


(1)一个生产者、一个消费者,公用一个缓冲区


这里我们设置三个信号量semptyfulls表示缓冲区的个数,初值为1empty表示缓冲区的大小,初值为20,即我们假设缓冲区最多能放20个产品;full表示缓冲区是否为空,初值为0。实现的程序如下:




程序中,我们用producer()来表示生产者,用consumer()来表示消费者,生产者生产一件产品要占用要判断缓冲区是否未满,即剩余空间empty减一之后是否还大于等于0,所以先对empty进行p操作,之后用p&s)判断缓冲区是否被占用,再进行生产(product加一并输出)后用v操作释放缓冲区,再执行v操作对full1判断是否大于0,即缓冲区是否为空,如果为不为空则继续执行,因为full的初值为0,而生产者进程执行的时间片完后轮到消费者进程,对full进行p操作是-1,消费者进程被堵塞再执行生产者进程,执行到v&full)时,full1变成0,所以唤醒消费者进程,p&full),full变成-1,再被堵塞,执行生产者进程,所以生产者进程和消费者进程会不断交替执行。为了使产品累加起来便于观察,我用延时函数delay使生产者生产产品的周期比消费者消费产品的周期要短。我们来观察程序的执行过程:





观察结果:首先生产者不停生产产品到10个,然后生产者一边生产、消费者一边消费,因为生产者的生产的速度比消费者消费的速度要快,所以产品还是在逐渐地累加一直到20,之后就是生产者生产一件产品、消费者消费一件产品,达到一个比较平衡的状态。


(2)一个生产者、一个消费者、公用n个环形缓冲区


这里比较特别的是缓冲池被分为多个环形缓冲区,也就是说,如果第一个缓冲区满了,那么生产者生产的产品只能放在第二个缓冲区中,如果第n个缓冲区满了,那么生产者就要再从第一个缓冲区开始放,消费者也是一样,如果第一个缓冲区里有产品而第二个里面没有,那么消费者就只能从第一个缓冲区中拿产品。因为缓冲区是环形的,要确定当前缓冲区是哪一个,我们可以用模运算求得。程序如下:


#include
semaphore s,empty,full;
int product[10]={0};
producer()
{
int in=0;
while(1)
{
delay(20);
p(&empty);
p(&s);
printf("Producer: There are %d products in NO.%d buffer\n",++product[in

首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇配置TC2.0运行环境 下一篇高级语言里的函数在汇编里的实现..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目