关于如何控制进程并发数

 
                              实现控制进程并发数
                                                                                                                (程如亮)
背景:
    在项目系统中,需要对渠道范围进行并发,在这过程中用到了并发,特对并发所牵扯的知识点做个全面的分析,作为以后学习的基础,也是对当初自己错误的认识做个改正。
分析:
并发最简单的理解就是多个进程同时运行。进程和程序是两个相对的概念。进程是程序的动态表现,程序就是静态的表现。在现代的操作系统中,并发不再算是很难操作的技术。
但并发具体是怎么回事?
在LINUX系列系统中,可以通过函数FORK()产生一个进程。产生的进程称为子进程。子进程会继承父进程的所有信息。继承后,父子进程不会同步。多进程有什么用了?为什么会产生多进程?
多进程就是为了充分利用系统资源。实际上,不存在两个或两个以上的进程在同时执行。当然在理解这句的前提是我们所用的机器不是多核的。
既然同时不能运行多个进程,为什么还要多进程?原因就是,让CPU去调度,去管理,总比我们人工管理来的更合理。更迅捷。
启动了多个进程,不是放任自流,可以实现他们之间互相通信。最起码他是在我们的控制范围之内。
程序分析:
1. if((j = fork()) == 0)
先从简单的分析,fork()个进程,返回值对于进程本身和父进程是不同的。从这简单的语句就能看出来。返回给父进程的是他本身的PID。PID就是进程标示号。在系统中,PID都是唯一的。 在后面就谈到的控制进程,就是通过他的PID。在进程内部也可以通过getpid()得到本身的PID。自己得到自己一般没什么大用,可以做其他之用,因为他是系统唯一的。不会冲突。看你本领发挥。
2. int main()
{
 If(fork() == 0)
 {            printf(“%d/n”,getppid());          }
else
{            printf(“%d/n”,getpid());           }
}
结果:打印两条输出语句。
我想无论谁对这代码没有任何疑问。但下面的代码就不一样了。
3. int main()
{
 If(fork() == 0)
 {            printf(“%d/n”,getppid());          }
            printf(“%d/n”,getpid());          
}
结果:打印三条输出语句。
这反应了父子进程之间的代码执行情况。
我想知道这么点内容后,足够学习其他的了。实际上要说的就是进程之间的通信。和父进程如何实现控制子进程。
4. 先来说父进程如何控制子进程。为什么要实现控制了?当然启动一个进程后,我们要得知他的状态,要完成我们的指定工作,不可能启动后就不管了。
一般可以通过如下的两个函数实现父进程对子进程的控制:
pid_t wait(int* status);
等待一个子进程结束或信号来到。
pid_t waitpid(pid_t pid ,int* status,int options);
   可以等待指定PID的子进程。
   如下的程序来说明下wait():
   pid_t pid;
   int status, i;
   if(fork() == 0){
printf(“this is the child process.pid = %d/n”,getpid());
exit(5);
}else{
sleep(1);
printf(“this is the parent process.wait for child…../n”);
pid = wait(&status);
i = WEXITSTATUS(status);
printf(“child’s pid = %d,exit status = %d/n”,pid ,i);
}
wait()的返回值就是子进程的PID。子进程的状态值可以通过宏WEXITSTATUS()得到。
状态值一般对我们编程不会起太大的作用,当然对于系统来说,有着很大的作用。父进程可以简单的通过PID来得到子进程的执行情况。控制多进程的方法不至这些简单的方法。再来谈谈进程通信。
5. 进程通信书本的方式如下:共享存储器,消息通信,共享文件。
先来谈共享存储器。要了解几个函数:
int shmget(key_t key,int size,int shmflg);
用来取得参数key所关联的共享内存识别代号。
void shmat(int shmid ,const void * shmaddr,int shmflg);
用来将参数shmid所指的共享内存和目前进程连接(attach).
int shmctl(int shmid , int cmd, struct shmid_ds *buf);
提供几种方式来控制共享内存。
Int shmdt(const void * shmaddr);
用来将先前用shmat()连接(attach)好的共享内存脱离(detach).
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define KEY 1234
#define SIZE  1024
int main()
{
       int shmid;
       char* shmaddr;
       struct shmid_ds buf;
       shmid = shmget(KEY,SIZE,IPC_CREAT|0600);       /*建立共享内存*/
       if(fork()==0)
       {
              shmaddr = (char*)shmat(shmid,NULL,0);
              strcpy(shmaddr,"hi!i am child process!/n");
              shmdt(shmaddr);
              return ;
       }
       else
       {
              sleep(3);                                 /*等子进程执行完毕*/
              shmctl(shmid,IPC_STAT,&buf);              /*取得共享内存状态*/
              printf("shm_segsz = %d bytes/n",buf.shm_segsz);/*打印共享内存状态*/
              printf("shm_cpid = %d/n",buf.shm_cpid);
              printf("shm_lpid = %d/n",buf.shm_lpid);
              shmaddr = (char*)shmat(shmid,NULL,0);
              printf("%s",shmaddr);                     /*显示共享内存内容*/
              shmdt(shmaddr);                         /*放开共享内存*/
              shmctl(shmid,IPC_RMID,NULL);           /*删除共享内存内容*/
       }
       return 0;
}
上面的程序实现了1024byte字节的内存进行共享.当初曾考虑了在父进程定义一个变量进行共享.那是个错误的想法.给出这段程序我想对控制进程数也是一个不错的想法.
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define key 1024
int main()
{
       int shmid;
       int* shmaddr;
       struct shmid_ds buf;
       shmid = shmget(key,32,IPC_CREAT|0600);/*建立共享内存*/
       if(fork()==0)
       {
              shmaddr = (int*)shmat(shmid,NULL,0);
             ++*shmaddr;
              printf("%dchengruliang",*shmaddr);
              sleep(10);
              shmdt(shmaddr);
              return ;
       }
       else
       {
              shmaddr = (int*)shmat(shmid,NULL,0);
              if(*shmaddr == 1)
                     printf("%d",*shmaddr); /*显示共享内存内容*/
              else
                     printf("hahahahahahahahhaahah");
              shmdt(shmaddr);
              shmctl(shmid,IPC_RMID,NULL);/*删除共享内存内容*/
       }
       return 0;
}
当初写这个程序的时候,还有点担心子进程不会迅速改变共享内存的内容.没想到是多虑了.比我想象的还要好.还要快捷.这个程序我在AIX上执行,父进程执行完,命令行提示都输出了,子进程才执行完毕.多进程太彻底了.
再来谈消息通信,先列出会用到的几个函数:
key_t ftok(char* pathname,char proj)
用来产生唯一的key.
int msgctl(int msqid,int cmd ,struct msqid_ds * buf);
提供了几种方式来控制信息队列的运作.
int msgget(key_t key ,int msgflg);
    依key建立信息队列.
int msgrcv(int msqid,struct msgbuf * msgp,int msgsz,long msgtyp,int msgflg)
    从信息队列读取数据信息.
int msgsnd(int msqid,struct msgbuf * msgp,int msgsz,int msgflg);
向信息队列输入数据信息.
int semctl(int semid,int semnum,int cmd,);
提供几种方式来控制信号队列的操作.
int semget(key_t key,int nsems,int semflg);
配置指定key所关联的信号队列.
int semop(int semid,struct sembuf * sops,unsigned nsops);
处理信号队列.
先来个简单的例子.反映基本问题.
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
 
#define KEY 1234
#define TEXT_SIZE 48
struct msgbuffer
{
       long mtype;
       char mtext[TEXT_SIZE];
}msgp;
 
int main()
{
       int msgid;
       msgid = msgget(KEY,IPC_CREAT|0600);
       if(fork() == 0)
       {
              msgp.mtype = 1;
              strcpy(msgp.mtext,"hi! i am child process!/n");
              msgsnd(msgid,&msgp,TEXT_SIZE,0);
              return ;
       }
       else
       {
              wait();
              msgrcv(msgid,&msgp,TEXT_SIZE,0,0);
              printf("parent receive mtext:%s",msgp.mtext);
              msgctl(msgid,IPC_RMID,NULL);
       }    
       return 0;
}
 
   (未完待续)
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值