中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 操作系统 > SCO_Unix
Unix操作系统并发进程数的控制
作者:未知 时间:2005-09-13 14:56 出处:ChinaUnix.net 责编:chinaitpower
              摘要:Unix操作系统并发进程数的控制

Unix操作系统并发进程数的控制
交通银行重庆分行电脑处 隆凡

--------------------------------------------------------------------------------
 
 
 
Unix操作系统常用于Client/Server结构中的Server(服务器端),在服务器端编程中,我们一般采用并发多进程的方式来接收处理Client(客户端)的服务请求。我们知道,在系统资源(CPU、内存、硬盘等)一定的情况下,系统所能负担的进程数量是有限的,如果超过这个限制,系统就会紊乱甚至崩溃。通讯超时过长、某种业务处理太慢,都会引起短时间内系统并发进程数的骤然增加,导致系统运行不稳定。因此,在Client/Server结构中,必须采取措施来控制并发进程的数量。在Unix系统中可采取多种方式来实现这种控制功能,如文件锁、信号量等。这里介绍一种简洁、可靠的方法,即采用Unix的消息队列来实现并发进程数的控制。
一、主要系统
1.int msgget (key_t key, int flags)
取得相应键值为key 的消息队列标识符。
2.int msgsnd (int qid , struct msgbuf * buf, int nbytes , int flags)
向标识符为qid 的消息队列发送长度为nbytes、已存于缓冲区buf 中的消息。
3.int msgrcv (int qid , struct msgbuf * buf ,int nbytes ,long mtype , int flags 
从标识符为qid 的消息队列中接收类型为mtype、长度为nbytes的消息队列到buf缓冲区中。
4.int msgctl (int qid ,int cmd , struct msgid_ds *sbuf 
按cmd表示的命令来控制标识符为qid的消息列。如果将cmd设为IPC_RMID,表示从系统中删除该消息队列。
Unix操作系统内核确保了上述对队列的读、写、控制等操作都是原子性的。当对同一队列同时进行读写时,内核自动将其转化为串行方式依次操作这一队列。
二、实现原理
进程数控制的实现原理是:初始化消息队列,并预先放入一定数量的消息,这预先放入的消息个数就是允许的相应进程最大并发数。当生成一个新进程时,从该消息队列中读取一个消息。如果此时无消息可读,表示进程数量已达到最大,返回失败;否则,接受客户端的处理请求。当该业务处理完成,须终止该进程时,将一个消息写回到队列中,以便系统可再生成新的进程进行业务处理。可以看出,队列中的消息已被模拟成一种令牌,当客户端申请业务处理时,应先取得一个令牌,业务处理完毕则将令牌归还。当令牌被全部占用时,服务器端将拒绝后续的业务处理请求。
三、应用实例
下面给出一个简单的范例来说明实现的方法,在SCO Open Server 5.0.4上编译通过。它可应用于实际的Client/Server环境中,并可沿此思想进一步拓展:如将业务处理进行分类,并按确定的优先次序来处理它们;动态控制不同类型的业务处理的最大进程数等等。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>

#define LIMMSGQ 0x20000l
#define MGFLAG 0777
struct lmsgstruct {
long mtype;
char mdata[32];
};

#define TESTTYPE 1

int Pliminit(int typenum,int procnum)
{
int msqid,i;
struct lmsgstruct rbuf;

msqid = msgget(LIMMSGQ+typenum, MGFLAG|IPC_CREAT);
if (msqid < 0)
{
return (-1);
}
while (msgrcv(msqid,(struct msgbuf *)&rbuf,sizeof(rbuf.mdata),0L,IPC_NOWAIT|MSG_NOERROR) >0);
rbuf.mtype = 1L; 
memset(rbuf.mdata,‘T',sizeof(rbuf.mdata));
rbuf.mdata[sizeof(rbuf.mdata)-1] = ‘\0';
for (i = 0;i< procnum;i++)
if (msgsnd(msqid,(struct msgbuf *)&rbuf,sizeof(rbuf.mdata),IPC_NOWAIT) < 0)
{
return (-2);
}
return(1);
}

int Plimread(int typenum)
{
int msqid,ret;
struct lmsgstruct rbuf;

msqid = msgget(LIMMSGQ+typenum, MGFLAG);
if (msqid < 0)
{
return (-1);
}
ret = msgrcv(msqid,(struct msgbuf *)&rbuf,sizeof(rbuf.mdata),1L,IPC_NOWAIT|MSG_NOERROR);
if ((int ret < (int sizeof(rbuf.mdata))
{
return (-2);
}
return(1);
}

int Plimwrite(int typenum)
{
int msqid,ret;
struct lmsgstruct rbuf;

msqid = msgget(LIMMSGQ+typenum, MGFLAG);
if (msqid < 0)
{
return (-1);
}
rbuf.mtype = 1L; 
memset(rbuf.mdata,‘M',sizeof(rbuf.mdata));
rbuf.mdata[sizeof(rbuf.mdata)-1] = ‘\0';
if (msgsnd(msqid,(struct msgbuf *)&rbuf,sizeof(rbuf.mdata),IPC_NOWAIT) < 0)
{
return (-2);
}
return(1);
}

int Plimend(int typenum)
{
int msqid;
struct msqid_ds ttt;
msqid = msgget(LIMMSGQ+typenum, MGFLAG);
if (msqid >= 0)
{
msgctl(msqid,IPC_RMID ,&ttt);
}
return(1);
}

main()
{
int ret;

ret = Pliminit(TESTTYPE,4); 
/*初始化队列,设定最大进程数为4 */
if (ret < 0)
{
printf(“mainliminit failed!\n");
exit(-1);
}
while (1) s
int c;
printf(“测试主程序\n");
printf(“1——生成1个子进程\n");
printf(“0——退出\n");
scanf(“%1d",&c); 
/*接收客户请求*/
if ( c == 0 
break;
ret = Plimread(TESTTYPE); 
/*检查正运行进程数是否已到最大并取得令牌*/
   if(ret < 0) 
/*正运行进程数已到最大,不进行业务处理*/
   {
   printf(“mainlimread failed!\n");
   printf(“system busy,please wait a moment!\n");
   }
   else
   if ( fork() == 0  
  /*正运行进程数未到最大,生成子进程*/
   { 
  /*进行相关业务处理*/
   sleep(10); 
  /*假定业务处理时间为 10s*/ 
   Plimwrite(TESTTYPE); 
  /*业务处理完毕,退还令牌,子进程退出*/ 
   exit(1);
   } 
   }
   Plimend(TESTTYPE); 
   /*撤消队列*/
   exit(1);
  }
  /* 编译方法: 
   cc -o ./ctltest ctltest.c 
   执行方法:
   ./ctltest
  如果在10秒钟内欲连续生成5个子进程,那么在生成第5个子进程时,将失败;
  等待10秒钟后,则可继续生成子进程。
  */

 htldm 回复于:2003-02-23 19:51:23
好!

 muzx 回复于:2003-02-23 19:51:58
见好就收!

 snowyshao 回复于:2003-02-24 08:57:03
用共享内存来实现不是更为方便?

 zhongjl 回复于:2003-02-24 18:44:40
多此一举!!

 apollo521 回复于:2003-02-25 20:54:27
不觉的麻烦吗?你是想告诉大家你会使用消息队列还是想告诉大家怎么方便、可行的控制并发进程数呢?想不通。。。用一个计数器实现不是很方便吗?

 海德 回复于:2003-02-25 22:46:11
你们可以说说你们的方法,具体点吧。 

 zhongzhu 回复于:2003-02-27 16:28:20
如果在写回之前程序被kill掉,如何办?
apollo521 :多进程你怎么用计数器?

 xzh2002 回复于:2003-02-27 16:40:12
好象用 ulimit 命令也可以

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有