操作系统实验三
要求:使用进程信号量实现生产者消费者
错误代码:
#include<semaphore.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
#include<stdlib.h>
struct Product{
int num;
struct Product *next;
};
struct Product *head;
int main(){
sem_t sem;
if(sem_init(&sem,1,1)<0){
perror("sem init error");
exit(0);
}
struct Product *p;
int i=fork(),loop=10,k;
printf("i=%d\n",i);
//child Customer
if(i==0){
for(k=0;k<loop;k++){
sem_wait(&sem);
if(head==NULL)
sleep(3);
p=head;
head=p->next;
printf("sell one NO.%d\n",p->num);
sem_post(&sem);
}
exit(0);
}
//parent producer
for(k=0;k<loop;k++){
sem_wait(&sem);
p=malloc(sizeof(struct Product));
p->num=rand()%1000+1;
p->next=head;
head=p;
printf("produce one NO.%d\n",p->num);
sem_post(&sem);
sleep(1);
}
exit(0);
}
错误:
1.父进程没有等待处理子进程
如果子进程在父进程前结束
(虽然exit,但为了方便父进程查看子进程结束时状态信息即怎么结束的等,仍会保留一些状态==zombie)
变成僵尸进程,
否则子进程则由init 进程领养;
2.注意与多线程下实现生产者消费者不同,进程间不会共享Product这个结构体
所以子进程中head指针一直为NULL .................................
原因:
使用fork时
子进程复制了父进程的堆栈段,数据段但不包括正文段,共用相同的正文段(代码段)(所以会执行同样的代码)
当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。(复制方式 :搜索 写时拷贝技术(copy-on-write))
所以这里变量实际是各自独立保存在物理空间的,信号量不是(创建时pshared==1 ,设置为共享);
//----------------------------------------------修改--------------------------------------------------
方法一:
使用IPC(Inter-Process Communication,进程间通信)对象和有名POSIX信号量
函数介绍:
1:shmget shm (share memory)
<span style="font-size:14px;">#include<sys/ipc.h>
#include<sys/shm.h>
int shmget(key_t key,size_t size,int shmflg)</span>
void * shmat(int shmid,const void * shmaddr,int shmflg)
int shmdt(const void * shmaddr)
注意:当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段, 而是把相关shmid_ds结构的shm_nattch域的值减1 , 当这个值为0时,内核才从物理上删除这个共享段 。
4.shmctl(control)
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
参数说明:
shmid 共享内存标识ID
cmd IPC_STAT得到共享内存的状态
IPC_SET改变共享内存的状态
IPC_RMID删除共享内存
buf 是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定;
注意:
1.IPC_RMID命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生最后一个进程离开这个共享段时。
2.当cmd为IPC_RMID时,第三个参数应为NULL。呵呵,大部分我们都是这样做,用这个函数删除共享内存。
过程:获得共享内存->建立共享->取消共享->删除内存