网络编程必备知识入门----十个子进程求和

十个子进程求和问题的学习
  各位读者朋友好,我是你们的好朋友IT黑铁!今天给大家分享的是我在Linux网络课程学习过程中,思考的第一个有意思的问题。在十个子进程求和中需要使用到的技术有:信号量、信号、共享内存。
  如何改进下面这个程序让其使用的共享内存只要一个字节???
  
#include<stdio.h>
#include<stdlib.h>
#include"sys/sem.h"
#include"sys/types.h"
#include"time.h"
#include"signal.h"
#include"sys/shm.h"
#include"unistd.h"
union semun{
    int val;
    struct semid_ds *buf;
    ushort *array;
};
int sem_id,shm_id;
int* pr;
void p(int sem_id)
{
    struct sembuf buf={0,-1,0};
    semop(sem_id,&buf,1);
}

void v(int sem_id)
{
    struct sembuf buf={0,1,0};
    semop(sem_id,&buf,1);    
}
void SIGINT_handler(int sql)
{
    int count,total;
    count=*pr;
    total=*(pr+1);
    printf("count=%d,total=%d\n",count,total);
    semctl(sem_id,IPC_RMID,0);    //删除信号量
    shmdt(pr);    //断开链接
    shmctl(shm_id,IPC_RMID,NULL);    //删除共享内存
    exit(0);
}
int main()
{
    signal(SIGINT,SIGINT_handler);
    sem_id=semget(IPC_PRIVATE,1,0666);
    union semun x;
    x.val=1;
    semctl(sem_id,0,SETVAL,x);
    shm_id=shmget(IPC_PRIVATE,2,0666);
    pr=(int*)shmat(shm_id,NULL,0);
    int i,is_child=0;
    for(i=0;i<10;i++)
    {
        int pid=fork();
        if(pid==0)
        {
            is_child=1;
            break;
        }
    }
    if(is_child==1)
    {
        p(sem_id);
        int count,num;
        srand(time(NULL)+getpid());
        count=*pr;
        count=count+1;
        num=1+rand()/((RAND_MAX+1u)/10);
        printf("count:%d,num:%d\n",count,num);
        *pr=count;
        *(pr+1)=*(pr+1)+num;
        v(sem_id);
        if(count==10)
        {
            kill(getppid(),SIGINT);
        }
    }
    else
    {
        while(1)
            pause();
    }
    return 0;
}

在解决这个问题前,我们先来理理这个程序求和的思路:1.注册一个信号用来在第10个子进程求和完毕后进行父进程输出求和结果 2.创建一个信号量并初始化

用来10个子进程之间对共享内存的并发控制 3.创建一个2个字节的共享内存,一个字节用于存count用于让当前求和进程判断自己是否是最后一个子进程,一个字节用于存和,并绑定在虚拟内存的指针上以便10个子进程访问 4.父进程创建10个子进程后,子进程进行求和,父进程消息循环等待最后一个子进程发来的信号,发来信号后调用信号处理函数完成求和。

 

在我们只能用一个字节的时候,那么肯定就不能使用count了,这时候我们来想,使用count的作用是得知最后一个子进程并向父进程发送信号,那么我们还能通过其他的方式来得知最后一个子进程是谁吗?起初我想错方向,想要通过数字编码的方式,但一个字节8位,编码实在不可取。后来仔细思索,我们可以完全使用信号量机制,当没有资源时,阻塞住当前进程,直到10个子进程求和完毕后,释放了10个资源使得父进程输出和,这样甚至都不需要使用信号!

#include<stdio.h>
#include<stdlib.h>
#include"sys/sem.h"
#include"sys/types.h"
#include"time.h"
#include"signal.h"
#include"sys/shm.h"
#include"unistd.h"
union semun{
	int val;
	struct semid_ds *buf;
	ushort *array;
};
int sem_id,shm_id;
int* pr;
void p_1(int sem_id)
{
	struct sembuf buf={0,-1,0};
	semop(sem_id,&buf,1);
}

void p_2(int sem_id)
{
	struct sembuf buf={1,-10,0};
	semop(sem_id,&buf,1);
}

void v_1(int sem_id)
{
	struct sembuf buf={0,1,0};
	semop(sem_id,&buf,1);	
}
void v_2(int sem_id)
{
	struct sembuf buf={1,1,0};
	semop(sem_id,&buf,1);	
}
int main()
{
	sem_id=semget(IPC_PRIVATE,2,0666);//定义一个信号量集
	union semun x;
	union semun y;
	x.val=1;
	y.val=0;
	semctl(sem_id,0,SETVAL,x);
	semctl(sem_id,1,SETVAL,y);
	shm_id=shmget(IPC_PRIVATE,1,0666);
	pr=(int*)shmat(shm_id,NULL,0);
	int i,is_child=0;
	for(i=0;i<10;i++)
	{
		int pid=fork();
		if(pid==0)
		{
			is_child=1;
			break;
		}
	}
	if(is_child==1)
	{
		p_1(sem_id);
		int num;
		srand(time(NULL)+getpid());
		num=1+rand()/((RAND_MAX+1u)/10);
		printf("num:%d\n",num);
		*pr=num+*pr;
		v_1(sem_id);
		v_2(sem_id);
	}
	else
	{
		p_2(sem_id);
		int total;
		total=*pr;
		printf("total=%d\n",total);
		semctl(sem_id,IPC_RMID,0);	//删除信号量
		shmdt(pr);	//断开链接
		shmctl(shm_id,IPC_RMID,NULL);	//删除共享内存
	}
	return 0;
}
	
而在具有忙等待的信号量经典定义下,信号量的值不能为负。
如果信号量的值为负,那么它的绝对值就是等待它的进程数。出现这种情况源于,在实现操作 wait() 时互换了递减和测试的顺序。

	

 以上就是本次十个子进程求和的分享!如有疑问或是指正请评论或私信我,我将及时回复你! 

 
posted @ 2022-06-27 20:56  炸天帮达令  阅读(73)  评论(0编辑  收藏  举报