linux c进程间通信

进程间通信

. 实验目的

1.了解Linux操作系统用户进程的编程。

2.了解Linux操作系统中进程间通信系统调用的使用方法。


. 实验内容

编写一个生产者-消费者程序组,支持多个生产者和消费者,生产者进程数为2

消费者进程数为3

生产者与消费者之间使用共享内存进行数据传递,并使用信号量对数据的内容进行保护。


具体要求如下:

  1. 共享内存大小为3字节,用于存储生产者产生的数据(字符)。如果其中某个单元存储的字符为0’,表示空闲,可以写入。

  2. 2个生产者:
    随机等待一段时间(1-5),往缓冲区添加一个数据,数据为‘1’-‘9’之间的随机字符。如果缓冲区已满,需要等待消费者取走数据后再添加。
    完成写入6个数据后退出。

  3. 3个消费者
    随机等待一段时间,从缓冲区读取数据,读完之后,把字符改为‘0’
    若缓冲区为空,等待生产者添加数据后再读取
    完成读取4个数据后退出。

  4. 每次往共享内存缓冲区读写数据时,需要在终端输出相应的提示信息,包括:进程id,读()时间(时分秒),读()前缓冲区字符情况,生产消费数据情况,如:

生产者***pid14:10:01 809 生产数据1

消费者*** 14:10:05 819 消费数据8



2.S1-可读(0) S2-可写(3)S3-可访问共享内存(1)

对于生产者:

PS2

PS3

写数据

VS3

VS1)

对于消费者:

PS1

PS3

读数据

VS3

VS2)



忽略英文注释。。懒得删。。

消费者

consumer.c

#include <time.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "semun.h"
struct share_memory{
	char a;
	char b;
	char c;
};

 int semaphore_p(int sem_id);
 int semaphore_v(int sem_id);

  int set_semvalue(int sem_id,int v);
 void del_semvalue(int sem_id);
 



int main(int argc, char *argv[])
{
    int tpid=fork();
    if(tpid==0) fork();
    int i;
    int pause_time;
    int sem_id,sem_idR,sem_idW;
    void * shared_memory =(void *)0;
    struct share_memory * shared_stuff;
    
    sem_idR = semget((key_t)12340, 1, 0666 | IPC_CREAT);
    sem_idW = semget((key_t)12350, 1, 0666 | IPC_CREAT);
    sem_id = semget((key_t)12360, 1, 0666 | IPC_CREAT);

    if(!set_semvalue(sem_idR,0)||!set_semvalue(sem_idW,3)||!set_semvalue(sem_id,1)){
	fprintf(stderr,"Failed to initialize semaphore\n");
	exit(EXIT_FAILURE);
    }
    int shmid;
    shmid=shmget((key_t)12370,sizeof(struct share_memory),0666|IPC_CREAT);
    if(shmid == -1){
    	fprintf(stderr,"shmget failed\n");
	exit(EXIT_FAILURE);

    }
    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1) {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }
    shared_stuff = (struct share_memory *)shared_memory;
//因为先运行消费者,所以初始化等工作理应放在消费者这里
	shared_stuff->a='0';
	shared_stuff->b='0';
	shared_stuff->c='0';
	int cnt=0;
    while(1){
	 srand((unsigned int)time(NULL));
 
	 if(cnt>=4){

 		printf("\n%d - finished\n", getpid());
		break;

	} 
	if (!semaphore_p(sem_idR)) exit(EXIT_FAILURE);
	/*if(shared_stuff->a=='0'&&shared_stuff->b=='0'&&shared_stuff->c=='0'){
                pause_time = rand() % 5+1;
                sleep(pause_time);
        }*/
	
        if (!semaphore_p(sem_id)) exit(EXIT_FAILURE);
	cnt++;
	char newConsum='0';
        if(shared_stuff->a!='0'){
		newConsum=shared_stuff->a;
		shared_stuff->a='0';
	}else if(shared_stuff->b!='0'){
		newConsum=shared_stuff->b;
		shared_stuff->b='0';
	}else if(shared_stuff->c!='0'){
		newConsum=shared_stuff->c;
		shared_stuff->c='0';
	}
	if(newConsum>'0'&&newConsum<='9'){
	struct   tm     *ptm; 
	long       ts; 
	int         y,m,d,h,n,s; 

	ts   =   time(NULL); 
	ptm   =   localtime(&ts); 
	printf("消费者 %d %ld:%ld:%ld 消费数据:%c 共享内存%c%c%c\n",(int)getpid(),(long)ptm->tm_hour,(long)ptm->tm_min,(long)ptm->tm_sec,newConsum,shared_stuff->a,shared_stuff->b,shared_stuff->c);
	}	
/* After the critical section, we call semaphore_v, setting the semaphore available,
 before going through the for loop again after a random wait. After the loop, the call
 to del_semvalue is made to clean up the code. */

        if (!semaphore_v(sem_id)) exit(EXIT_FAILURE);
        if (!semaphore_v(sem_idW)) exit(EXIT_FAILURE);
	srand((unsigned int)time(NULL));

        pause_time = rand() % 5+1;
        sleep(pause_time);
    }    


   {
        sleep(10);
        del_semvalue(sem_idR);
        del_semvalue(sem_idW);
        del_semvalue(sem_id);
    }
 
        
   if (shmdt(shared_memory) == -1) {//将共享内存从当前进程中分离
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }
  if(shmctl(shmid,IPC_RMID,NULL)==-1){//删除该进程对共享内存的连接(该共享内存一直存在直至最后一个连接断开)
	fprintf(stderr,"detach erro");
	exit(EXIT_FAILURE);

	}          
  

    exit(EXIT_SUCCESS);
}


/* semaphore_p changes the semaphore by -1 (waiting). */

 int semaphore_p(int sem_id)
{
    struct sembuf sem_b;
    
    sem_b.sem_num = 0;
    sem_b.sem_op = -1; /* P() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        fprintf(stderr, "semaphore_p failed\n");
        return(0);
    }
    return(1);
}

/* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
 so that the semaphore becomes available. */

 int semaphore_v(int sem_id)
{
    struct sembuf sem_b;
    
    sem_b.sem_num = 0;
    sem_b.sem_op = 1; /* V() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        fprintf(stderr, "semaphore_v failed\n");
        return(0);
    }
    return(1);
}
/* The function set_semvalue initializes the semaphore using the SETVAL command in a
 semctl call. We need to do this before we can use the semaphore. */

 int set_semvalue(int sem_id,int v)
{
    union semun sem_union;

    sem_union.val = v;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
    return(1);
}

/* The del_semvalue function has almost the same form, except the call to semctl uses
 the command IPC_RMID to remove the semaphore's ID. */

 void del_semvalue(int sem_id)
{
    union semun sem_union;
    
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        fprintf(stderr, "Failed to delete semaphore\n");
}

生产者

producer.c

#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include "semun.h"
struct  share_memory{
	char a;
	char b;
	char c;
};
 int semaphore_p(int sem_id);
 int semaphore_v(int sem_id);
 int set_semvalue(int sem_id);
 void del_semvalue(int sem_id);
 


int main(int argc, char *argv[])
{
	fork();
    int i;
    int pause_time;
    int sem_id,sem_idR,sem_idW;
    void * shared_memory=(void *)0;
    struct share_memory * shared_stuff;
    
    sem_idR = semget((key_t)12340, 1, 0666 | IPC_CREAT);
    sem_idW = semget((key_t)12350, 1, 0666 | IPC_CREAT);
    sem_id = semget((key_t)12360, 1, 0666 | IPC_CREAT);


    int shmid;
    shmid=shmget((key_t)12370,sizeof(struct share_memory),0666|IPC_CREAT);
    if(shmid == -1){
    	fprintf(stderr,"shmget failed\n");
	exit(EXIT_FAILURE);

    }
    shared_memory  = shmat(shmid, (void *)0, 0);
    if (shared_memory  == (void *)-1) {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }
	shared_stuff=(struct share_memory *) shared_memory;
	if(shared_stuff==NULL){fprintf(stderr,"shared_stuff==NULL\n");return 1;}
	printf("Memory attached at %X %d\n",(int)shared_stuff,sizeof(struct share_memory));
    
	
    for(i = 0; i < 6; i++) {        
	if (!semaphore_p(sem_idW)) exit(EXIT_FAILURE);
	/*if(shared_stuff->a!='0'&&shared_stuff->b!='0'&&shared_stuff->c!='0'){
		pause_time = rand() % 5+1;
       		sleep(pause_time);
	}*/
        if (!semaphore_p(sem_id)) exit(EXIT_FAILURE);
       //	puts("provider enter");
	 srand((unsigned int)time(NULL)*(i+3));
	
	int tmp=rand()%9+1;
	char newProduct;
        if(shared_stuff->a=='0'){
		shared_stuff->a+=tmp;
		newProduct=shared_stuff->a;
		
	}else if(shared_stuff->b=='0'){
		shared_stuff->b+=tmp;
		newProduct=shared_stuff->b;
	}else if(shared_stuff->c=='0'){
		shared_stuff->c+=tmp;
		newProduct=shared_stuff->c;
	}
	if(newProduct>'0'&&newProduct<='9'){
	
	struct   tm     *ptm;
        long       ts;
        int         y,m,d,h,n,s;

        ts   =   time(NULL);
        ptm   =   localtime(&ts);
        printf("生产者 %d  %ld:%ld:%ld 生成数据:%c 共享内存:%c%c%c\n",(int)getpid(),(long)ptm->tm_hour,(long)ptm->tm_min,(long)ptm->tm_sec,newProduct,shared_stuff->a,shared_stuff->b,shared_stuff->c);
        fflush(stdout);
	}
     	
/* After the critical section, we call semaphore_v, setting the semaphore available,
 before going through the for loop again after a random wait. After the loop, the call
 to del_semvalue is made to clean up the code. */
 
        if (!semaphore_v(sem_id)) exit(EXIT_FAILURE);
        if (!semaphore_v(sem_idR)) exit(EXIT_FAILURE);
	//puts("provider leave");
	srand((unsigned int)time(NULL)*(i+3));

        pause_time = rand() % 5+1;
        sleep(pause_time);
   
    }    

 
  if(shmdt(shared_stuff) == -1){//将共享内存从当前进程中分离
        fprintf(stderr,"shmdt failed \n");
        exit(EXIT_FAILURE);
        }
 if(shmctl(shmid,IPC_RMID,NULL)==-1){//删除该进程对共享内存的连接(该共享内存一直存在直至最后一个连接断开)
	fprintf(stderr,"detach erro");
	exit(EXIT_FAILURE);

	}      
      
    exit(EXIT_SUCCESS);
}


/* semaphsrore_p changes the semaphore by -1 (waiting). */

 int semaphore_p(int sem_id)
{
    struct sembuf sem_b;

    sem_b.sem_num = 0;
    sem_b.sem_op = -1; /* P() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        printf("semaphore_p failed\n");
        return(0);
    }
	
    return(1);
}

/* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
 so that the semaphore becomes available. */

 int semaphore_v(int sem_id)
{
    struct sembuf sem_b;
   
    sem_b.sem_num = 0;
    sem_b.sem_op = 1; /* V() */
    sem_b.sem_flg = SEM_UNDO;
    if (semop(sem_id, &sem_b, 1) == -1) {
        printf( "semaphore_v failed\n");
        return(0);
    }
	
    return(1);
}
/* The function set_semvalue initializes the semaphore using the SETVAL command in a
 semctl call. We need to do this before we can use the semaphore. */

 int set_semvalue(int sem_id)
{
    union semun sem_union;

    sem_union.val = 1;
    if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
    return(1);
}

/* The del_semvalue function has almost the same form, except the call to semctl uses
 the command IPC_RMID to remove the semaphore's ID. */

 void del_semvalue(int sem_id)
{
    union semun sem_union;
    
    if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        fprintf(stderr, "Failed to delete semaphore\n");
}

./consumer.exe &

./producer.exe





查看信号量可用 ipcs -s查看

查看共享内存可用 ipcs -m 查看

执行时出现“段错误,核心已转储”可禅看头文件 sys/shm.h 是否已经包含

执行时,时间函数调用出现问题,查看 头文件time.h是否以及包含

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值