??xml version="1.0" encoding="utf-8" standalone="yes"?>国产在线三区,三级电影一区,日本一区二区三区dvd视频在线http://www.aygfsteel.com/lusm/category/20008.html<font size="2"color="#6ac893">喜欢交流 怺促进 共同q步</font><br> zh-cnWed, 16 Jan 2008 20:11:30 GMTWed, 16 Jan 2008 20:11:30 GMT60QT hello worldhttp://www.aygfsteel.com/lusm/archive/2008/01/15/175563.htmlqL~@@~qL~@@~Tue, 15 Jan 2008 15:22:00 GMThttp://www.aygfsteel.com/lusm/archive/2008/01/15/175563.htmlhttp://www.aygfsteel.com/lusm/comments/175563.htmlhttp://www.aygfsteel.com/lusm/archive/2008/01/15/175563.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/175563.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/175563.htmlD很多初学者无所适从Q?
于是本h写下此文Q用简单的ҎQ去掉所谓的VC整合qt的繁琐步骤,带大家进入QT世界!!  阅读全文

qL~@@~ 2008-01-15 23:22 发表评论
]]>
Linux Assemblyhttp://www.aygfsteel.com/lusm/archive/2007/12/19/168795.htmlqL~@@~qL~@@~Wed, 19 Dec 2007 08:54:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/12/19/168795.htmlhttp://www.aygfsteel.com/lusm/comments/168795.htmlhttp://www.aygfsteel.com/lusm/archive/2007/12/19/168795.html#Feedback2http://www.aygfsteel.com/lusm/comments/commentRss/168795.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/168795.html阅读全文

qL~@@~ 2007-12-19 16:54 发表评论
]]>
由尚L列讲座之linux内核~程入门http://www.aygfsteel.com/lusm/archive/2007/09/06/143283.htmlqL~@@~qL~@@~Thu, 06 Sep 2007 13:49:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/09/06/143283.htmlhttp://www.aygfsteel.com/lusm/comments/143283.htmlhttp://www.aygfsteel.com/lusm/archive/2007/09/06/143283.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/143283.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/143283.html阅读全文

qL~@@~ 2007-09-06 21:49 发表评论
]]>
《linux内核分析视频教程?/title><link>http://www.aygfsteel.com/lusm/archive/2007/09/06/143276.html</link><dc:creator>qL~@@~</dc:creator><author>qL~@@~</author><pubDate>Thu, 06 Sep 2007 13:09:00 GMT</pubDate><guid>http://www.aygfsteel.com/lusm/archive/2007/09/06/143276.html</guid><wfw:comment>http://www.aygfsteel.com/lusm/comments/143276.html</wfw:comment><comments>http://www.aygfsteel.com/lusm/archive/2007/09/06/143276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lusm/comments/commentRss/143276.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lusm/services/trackbacks/143276.html</trackback:ping><description><![CDATA[     摘要:   <a href='http://www.aygfsteel.com/lusm/archive/2007/09/06/143276.html'>阅读全文</a><img src ="http://www.aygfsteel.com/lusm/aggbug/143276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lusm/" target="_blank">qL~@@~</a> 2007-09-06 21:09 <a href="http://www.aygfsteel.com/lusm/archive/2007/09/06/143276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[视频]嵌入式系l应用与开发技?中国U技大学[C++语言E序设计]http://www.aygfsteel.com/lusm/archive/2007/07/30/133428.htmlqL~@@~qL~@@~Mon, 30 Jul 2007 12:46:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/07/30/133428.htmlhttp://www.aygfsteel.com/lusm/comments/133428.htmlhttp://www.aygfsteel.com/lusm/archive/2007/07/30/133428.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/133428.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/133428.html阅读全文

qL~@@~ 2007-07-30 20:46 发表评论
]]>
世界上最的操作pȝhttp://www.aygfsteel.com/lusm/archive/2007/06/21/125508.htmlqL~@@~qL~@@~Thu, 21 Jun 2007 03:47:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/06/21/125508.htmlhttp://www.aygfsteel.com/lusm/comments/125508.htmlhttp://www.aygfsteel.com/lusm/archive/2007/06/21/125508.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/125508.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/125508.html阅读全文

qL~@@~ 2007-06-21 11:47 发表评论
]]>
[转]C与脚本的混合~程http://www.aygfsteel.com/lusm/archive/2007/04/13/110459.htmlqL~@@~qL~@@~Fri, 13 Apr 2007 07:27:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/04/13/110459.htmlhttp://www.aygfsteel.com/lusm/comments/110459.htmlhttp://www.aygfsteel.com/lusm/archive/2007/04/13/110459.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/110459.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/110459.html    而C语言固然有种U优势,但不可否认,很多场合下,用脚本语a更ؓ方便Q比如我们将举例说明的对配置文g的处理?nbsp;

先看看我们示例程序的dQ?nbsp;

假设我们有一个用c写的E序Q它有一个配|文?nbsp;user.confQ保存了一些用户信息,user.conf定义如下Q?nbsp;

1Q、以 # 开头的行ؓ注释行,不做处理 

2Q、允许空?nbsp;

3Q、如果不??Q那么就是有效的数据Q格式如?nbsp;


# user.conf: configure file for user 
# username age *** country 
tom 20 male us 
chen 22 female cn 


每一列分?个字D,字段之间用一个或多个I白字符Q空格或者制表符Q隔开Q字D依ơ是 姓名、年龄、性别、国?nbsp;

我们的cE序要完成对 user.conf的添加、删除、编辑、查?nbsp;

q样一个简单的dQ用c处理h不算复杂Q不q也是要q功夫的,而如果用脚本语言来做Q却很简单,能不能在c中调用脚本来完成d了? 

Awk是linux上一U脚本语aQ它的长处在于处理有一定格式规则的文gQ例如咱们的user.conf。关?nbsp;awk 的资料有很多Qoreilly公司Z专门?nbsp;awk ~程的书c,|上也是可以下蝲到的。你也可以直?nbsp;man awk看看?nbsp;

我们先看看如何用 shell l合 awk来完成上qCQ务: 

1Q?nbsp;d一条记?nbsp;

例如Q要d jack 18 male us q样一条记录,可以单的用重定向功能 

Echo -e "jack 18 male us" >> user.conf 

现在Q这条记录被d?nbsp;user.conf末尾了?nbsp;

2Q?nbsp;删除一条记?nbsp;

例如Q现在要删除用户 chen 的信?nbsp;

cat user.conf | awk ‘!/^chen[[:blank:]]+/ {print}' > tmp.conf; mv -f tmp.conf user.conf 

3Q、编辑一条记?nbsp;
现在Q想?nbsp;tom的性别改ؓ female 

cat user.conf | awk ‘{if($0 ~ /^tom[[:blank:]]+/) print $1 $2 female $3; else print}' 

通过 system()q个函数Q我们就可以?nbsp;c 中调用以上脚本,完成d了?nbsp;
但是Qsystem() 用v来还是觉得不爽,它的不是只能执行脚本,却无法获得脚本的输出数据Q而这通常是我们进一步处理的数据来源。(在shell和perl中,可以通过反引? `` )来取得命令的输出l果Q?nbsp;一个解军_法是把输出结果重定向C个时文件中Q然后在c中读取文Ӟ获取数据Q最后当然还要删除这个文件。不q,q个ҎL让h觉得有一点点不爽Q如果能直接把脚本执行中输出的数据输到我们的~冲区来更好了?nbsp;


我写了个函敎ͼ?nbsp;my_system()Q通过道以及重定向,实现了以上想法。函数原型如下: 

int my_system(const char* pCmd, char* pResult, int size)Q?nbsp;

输出数据被保存到 pResult所指向的缓冲区中,~冲区大ؓ sizeQ最多可以保?nbsp;size-1的数据?nbsp;

函数的实现放在本文的最?nbsp;

有了q个函数以后Q在 c中调用脚本就更方便了Q我们可以通过它来实现?nbsp;user.conf的查询?nbsp;

4Q、查询一个记?nbsp;
例如Q我们要获取 tom 的性别 
可以用脚本这h实现Q?nbsp;

cat user.conf | awk ‘/^tom[[:blank:]]+/ {print $3}' 

脚本的执行结果是 tom的性别 male被输出到屏幕?nbsp;

在我们的 cE序中,如此调用 my_system()Q?nbsp;

char buf[101]; 
my_system("cat user.conf | awk ‘/^tom[[:blank:]]+/ {print $3}'", buf, 101); 


调用完以后,buf中的数据是 "male"了,怎么Pq算方便吧? 

以上只是用结合脚本完成了一个比较简单的dQ所以我没有把这些脚本单独Ş成脚本文件。如果你善于使用 perl、shell、awkQ那么可以写出更强大的脚本文件来处理更复杂的问题Q然后通过cM my_system( )的方法,?nbsp;c/c++{其它语a中取得脚本的输出l果Q实现有的"混合~程"?nbsp;

希望你能从中得到乐趣Q?nbsp;

#include 
#include 
#include 
#include 
#include 
static int my_system(const char* pCmd, char* pResult, int size) 
{
int fd[2]; 
int pid; 
int count; 
int left; 
char* p = 0
int maxlen = size – 1
memset(pResult, 
0, size); 
if(pipe(fd)) 

printf(
"pipe error\n"); 
return –1
}
 
if((pid = fork()) == 0
{// chile process 
int fd2[2]; 
if(pipe(fd2)) 

printf(
"pipe2 error\n"); 
return –1
}
 
close(
1); 
dup2(fd2[
1],1); 
close(fd[
0]); 
close(fd2[
1]); 
system(pCmd); 
read(fd2[
0], pResult, maxlen); 
pResult[strlen(pResult)
-1= 0
write(fd[
1], pResult, strlen(pResult)); 
close(fd2[
0]); 
exit(
0); 
}
 
// parent process 
close(fd[1]); 
= pResult; 
left 
= maxlen; 
while((count = read(fd[0], p, left))) 

+= count; 
left 
-= count; 
if(left == 0
break
}
 
close(fd[
0]); 
return 0
}
 
int main(void

char result[1025]; 
my_system(
"/sbin/ifconfig", result, 1025); 
printf(
"the result is\n\n%s\n", result); 
return 0
}



qL~@@~ 2007-04-13 15:27 发表评论
]]>
llinux C~存的分配和使用Ҏhttp://www.aygfsteel.com/lusm/archive/2007/04/07/109158.htmlqL~@@~qL~@@~Sat, 07 Apr 2007 14:53:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/04/07/109158.htmlhttp://www.aygfsteel.com/lusm/comments/109158.htmlhttp://www.aygfsteel.com/lusm/archive/2007/04/07/109158.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/109158.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/109158.html        q几天做 C socket 有个朋友遇到问题Q答应帮忙解决的Q于是上|?br>找找相关资料Q可惜实在是难找Q郁闷上图书馆翻MQ发C本叫
《linux内核分析及编E?-倪?的书讲到了,呵呵happyQ借回来looklook;
Z把要用到的内Ҏ出来发个文章Q有需要的朋友可以看看Q改资料虽然
短,但我想会很有用;linux 下的C~程pȝ源码有着密切的关p,我想q?br>是编E的隑ֺ所在本来寒假是惛_点C的,不知道这么搞的搞到java那里MQ?br>看来q是要花Ҏ间学学C了,不然完了;
呵呵Q全是废话来的,看资料吧Q?img height=20 src="http://www.aygfsteel.com/Emoticons/QQ/lol.gif" width=20 border=0>


linux下用C实现~存分配和?/strong>


kmem_cache_create 函数是给一个对象空间分配一个缓冲区Q下面是它的例子Q在kernel/fork.c中)


void _init proc_caches_init(void){
 
 vm_area_cachep 
= kmem_cache_create(
             
"vm_area_struct",
             
sizeof(vm_area_struct),
             SLAB_PANIC,NULL,NULL
               );
 
 }


kmem_cache_alloc 是从指定的缓冲区中分配一个对象,它的例子如下Q?br>


static inline int dup_mmap(struct mm_struct * mm,struct mm_struct *oldmm){
struct vm_area_struct *mpnt,*tmp,**pprev;
.
   tmp 
= kmem_cache_alloc(vm_area_cachep,
                         SLAB_KERNAEL
                       );
.
}


kmalloc 函数是分析一个大ؓ size 的内存块Q下面是一个应用例子(在kernel/power/pm.cQ?/span>


struct pm_dev *pm_register(pm_dev_t type,
                  unsigned 
long id,
                  pm_callback callback   
                  )
{
    
//GEP_KERNEL表示正在q行的内核态的q程分配I间Q可以陷入睡?/span>
struct pm_dev *dev = kmalloc (sizeof(struct pm_pev),GFP_KERNEL);
..
}


vmalloc 函数分配一D连l的 size 大小的虚拟内存,其对应物理页可不q箋。下面是一个应用例
子(在security/selinux/ss/avtab.c中)Q?/span>


int avtab_init(struct avtab *h)
    
{
      ..
      h
->htable = vmalloc(sizeof(*(h->htable))*AVTAB_SIZE);
      ..
       }





qL~@@~ 2007-04-07 22:53 发表评论
]]>
[转]Linux 环境q程间通信Q六Q~~~~~~~套接?/title><link>http://www.aygfsteel.com/lusm/archive/2007/04/04/108300.html</link><dc:creator>qL~@@~</dc:creator><author>qL~@@~</author><pubDate>Tue, 03 Apr 2007 16:02:00 GMT</pubDate><guid>http://www.aygfsteel.com/lusm/archive/2007/04/04/108300.html</guid><wfw:comment>http://www.aygfsteel.com/lusm/comments/108300.html</wfw:comment><comments>http://www.aygfsteel.com/lusm/archive/2007/04/04/108300.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lusm/comments/commentRss/108300.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lusm/services/trackbacks/108300.html</trackback:ping><description><![CDATA[     摘要: 在本专题的前面几个部分,如消息队列、信L、共享内存等Q都是基于Sys V的IPC机制q行讨论的,它们的应用局限在单一计算机内的进E间通信Q基于BSD套接口不仅可以实现单机内的进E间通信Q还可以实现不同计算E之间的通信。本文将主要介绍BSD套接口(socketsQ,以及Z套接口的重要而基本的API? 一个套接口可以看作是进E间通信的端点(endpointQ,每个套接口的名字都是唯一的(?..  <a href='http://www.aygfsteel.com/lusm/archive/2007/04/04/108300.html'>阅读全文</a><img src ="http://www.aygfsteel.com/lusm/aggbug/108300.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lusm/" target="_blank">qL~@@~</a> 2007-04-04 00:02 <a href="http://www.aygfsteel.com/lusm/archive/2007/04/04/108300.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Linux环境q程间通信Q五Q~~~~~~~׃n内存http://www.aygfsteel.com/lusm/archive/2007/04/03/108297.htmlqL~@@~qL~@@~Tue, 03 Apr 2007 15:59:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/04/03/108297.htmlhttp://www.aygfsteel.com/lusm/comments/108297.htmlhttp://www.aygfsteel.com/lusm/archive/2007/04/03/108297.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/108297.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/108297.html阅读全文

qL~@@~ 2007-04-03 23:59 发表评论
]]>
[转]Linux环境q程间通信Q四Q~~~~~~~信号?/title><link>http://www.aygfsteel.com/lusm/archive/2007/04/03/108296.html</link><dc:creator>qL~@@~</dc:creator><author>qL~@@~</author><pubDate>Tue, 03 Apr 2007 15:57:00 GMT</pubDate><guid>http://www.aygfsteel.com/lusm/archive/2007/04/03/108296.html</guid><wfw:comment>http://www.aygfsteel.com/lusm/comments/108296.html</wfw:comment><comments>http://www.aygfsteel.com/lusm/archive/2007/04/03/108296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lusm/comments/commentRss/108296.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lusm/services/trackbacks/108296.html</trackback:ping><description><![CDATA[     摘要:   <a href='http://www.aygfsteel.com/lusm/archive/2007/04/03/108296.html'>阅读全文</a><img src ="http://www.aygfsteel.com/lusm/aggbug/108296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lusm/" target="_blank">qL~@@~</a> 2007-04-03 23:57 <a href="http://www.aygfsteel.com/lusm/archive/2007/04/03/108296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]Linux环境q程间通信Q三Q~~~~~~~消息队列http://www.aygfsteel.com/lusm/archive/2007/04/03/108295.htmlqL~@@~qL~@@~Tue, 03 Apr 2007 15:55:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/04/03/108295.htmlhttp://www.aygfsteel.com/lusm/comments/108295.htmlhttp://www.aygfsteel.com/lusm/archive/2007/04/03/108295.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/108295.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/108295.html本系列文章中的前两部分,我们探讨道及信号两U通信机制Q本文将深入W三部分Q介l系l?V 消息队列及其相应 API?/p>

消息队列Q也叫做报文队列Q能够克服早期unix通信机制的一些缺炏V作为早期unix通信机制之一的信可够传送的信息量有限,后来虽然POSIX 1003.1b在信L实时性方面作了拓q,使得信号在传递信息量斚w有了相当E度的改q,但是信号q种通信方式更像"x"的通信方式Q它要求接受信号的进E在某个旉范围内对信号做出反应Q因此该信号最多在接受信号q程的生命周期内才有意义Q信h传递的信息是接q于随进E持l的概念Qprocess-persistentQ,?附录 1Q管道及有名道及有名管道则是典型的随进E持lIPCQƈ且,只能传送无格式的字节流无疑会给应用E序开发带来不便,另外Q它的缓冲区大小也受到限制?

消息队列是一个消息的链表。可以把消息看作一个记录,h特定的格式以及特定的优先U。对消息队列有写权限的进E可以向中按照一定的规则d新消息;Ҏ息队列有L限的q程则可以从消息队列中读走消息。消息队列是随内核持l的Q参?附录 1Q?

目前主要有两U类型的消息队列QPOSIX消息队列以及pȝV消息队列Q系lV消息队列目前被大量用。考虑到程序的可移植性,新开发的应用E序应尽量用POSIX消息队列?/p>

在本pd专题的序Q深ȝ解Linuxq程间通信QIPCQ)中,提到对于消息队列、信L、以及共享内存区来说Q有两个实现版本QPOSIX的以及系lV的。Linux内核Q内?.4.18Q支持POSIX信号灯、POSIX׃n内存Z及POSIX消息队列Q但对于LLinux发行版本之一redhad8.0Q内?.4.18Q,q没有提供对POSIXq程间通信API的支持,不过应该只是旉上的事?/p>

因此Q本文将主要介绍pȝV消息队列及其相应API?在没有声明的情况下,以下讨论中指的都是系lV消息队列?/b>

一、消息队列基本概?/span>

  1. pȝV消息队列是随内核持箋的,只有在内栔Rh者显C删除一个消息队列时Q该消息队列才会真正被删除。因此系l中记录消息队列的数据结构(struct ipc_ids msg_idsQ位于内怸Q系l中的所有消息队列都可以在结构msg_ids中找到访问入口?
  2. 消息队列是一个消息的链表。每个消息队列都有一个队列头Q用l构struct msg_queue来描qͼ参见 附录 2Q。队列头中包含了该消息队列的大量信息Q包括消息队列键倹{用户ID、组ID、消息队列中消息数目{等Q甚臌录了最q对消息队列dq程的ID。读者可以访问这些信息,也可以设|其中的某些信息?
  3. 下图说明了内怸消息队列是怎样建立赯pȝQ?
    其中Qstruct ipc_ids msg_ids是内怸记录消息队列的全局数据l构Qstruct msg_queue是每个消息队列的队列头?


从上囑֏以看出,全局数据l构 struct ipc_ids msg_ids 可以讉K到每个消息队列头的第一个成员:struct kern_ipc_permQ而每个struct kern_ipc_perm能够与具体的消息队列对应h是因为在该结构中Q有一个key_tcd成员keyQ而key则唯一定一个消息队列。kern_ipc_perml构如下Q?/p>
struct kern_ipc_perm{   //内核中记录消息队列的全局数据l构msg_ids能够讉K到该l构Q?
            key_t   key;    //该键值则唯一对应一个消息队?
            uid_t   uid;
            gid_t   gid;
uid_t   cuid;
gid_t   cgid;
mode_t  mode;
unsigned long seq;
}





回页?/font>


二、操作消息队?/span>

Ҏ息队列的操作无非有下面三U类型:

1?打开或创建消息队?
消息队列的内核持l性要求每个消息队列都在系l范围内对应唯一的键|所以,要获得一个消息队列的描述字,只需提供该消息队列的键值即可;

注:消息队列描述字是由在pȝ范围内唯一的键值生成的Q而键值可以看作对应系l内的一条\l?/p>

2?d操作

消息d操作非常单,对开发h员来_每个消息都类似如下的数据l构Q?/p>
struct msgbuf{
long mtype;
char mtext[1];
};

mtype成员代表消息cdQ从消息队列中读取消息的一个重要依据就是消息的cdQmtext是消息内容,当然长度不一定ؓ1。因此,对于发送消息来_首先预置一个msgbuf~冲区ƈ写入消息cd和内容,调用相应的发送函数即可;对读取消息来_首先分配q样一个msgbuf~冲区,然后把消息读入该~冲区即可?/p>

3?获得或设|消息队列属性:

消息队列的信息基本上都保存在消息队列头中Q因此,可以分配一个类g消息队列头的l构(struct msqid_dsQ见 附录 2)Q来q回消息队列的属性;同样可以讄该数据结构?






消息队列API

1、文件名到键?/strong>

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj)Q?


它返回与路径pathname相对应的一个键倹{该函数不直接对消息队列操作Q但在调用ipc(MSGGET,?或msgget()来获得消息队列描q字前,往往要调用该函数。典型的调用代码是:

key=ftok(path_ptr, 'a');
    ipc_id=ipc(MSGGET, (int)key, flags,0,NULL,0);
    ?


2、linux为操作系lVq程间通信的三U方式(消息队列、信L、共享内存区Q提供了一个统一的用L面:
int ipc (unsigned int call, int first, int second, int third, void * ptr, long fifth);

W一个参数指明对IPC对象的操作方式,Ҏ息队列而言共有四种操作QMSGSND、MSGRCV、MSGGET以及MSGCTLQ分别代表向消息队列发送消息、从消息队列d消息、打开或创建消息队列、控制消息队列;first参数代表唯一的IPC对象Q下面将介绍四种操作?/p>

  • int ipc( MSGGET, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgget( (key_t)firstQsecond)?
  • int ipc( MSGCTL, intfirst, intsecond, intthird, void*ptr, longfifth)
    与该操作对应的系lV调用为:int msgctl( firstQsecond, (struct msqid_ds*) ptr)?
  • int ipc( MSGSND, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgsnd( first, (struct msgbuf*)ptr, second, third)?
  • int ipc( MSGRCV, intfirst, intsecond, intthird, void*ptr, longfifth);
    与该操作对应的系lV调用为:int msgrcv( firstQ?struct msgbuf*)ptr, second, fifth,third)Q?

注:本h不主张采用系l调用ipc()Q而更們֐于采用系lV或者POSIXq程间通信API。原因如下:

  • 虽然该系l调用提供了l一的用L面,但正是由于这个特性,它的参数几乎不能l出特定的实际意义(如以first、second来命名参敎ͼQ在一定程度上造成开发不ѝ?
  • 正如ipc手册所说的Qipc()是linux所Ҏ的,~写E序时应注意E序的移植性问题;
  • 该系l调用的实现不过是把pȝV IPC函数q行了封装,没有M效率上的优势Q?
  • pȝV在IPC斚w的API数量不多QŞ式也较简z?

3.pȝV消息队列API
pȝV消息队列API共有四个Q用时需要包括几个头文gQ?

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>


1Qint msgget(key_t key, int msgflg)

参数key是一个键|由ftok获得Qmsgflg参数是一些标志位。该调用q回与健值key相对应的消息队列描述字?/p>

在以下两U情况下Q该调用创Z个新的消息队列:

  • 如果没有消息队列与健值key相对应,q且msgflg中包含了IPC_CREAT标志位;
  • key参数为IPC_PRIVATEQ?

参数msgflg可以Z下:IPC_CREAT、IPC_EXCL、IPC_NOWAIT或三者的或结果?/p>

调用q回Q?/b>成功q回消息队列描述字,否则q回-1?

注:参数key讄成常数IPC_PRIVATEq不意味着其他q程不能讉K该消息队列,只意味着卛_创徏新的消息队列?/p>

2Qint msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg);
该系l调用从msgid代表的消息队列中d一个消息,q把消息存储在msgp指向的msgbufl构中?

msqid为消息队列描q字Q消息返回后存储在msgp指向的地址Qmsgsz指定msgbuf的mtext成员的长度(x息内容的长度Q,msgtyp求读取的消息cdQ读消息标志msgflg可以Z下几个常值的或:

  • IPC_NOWAIT 如果没有满条g的消息,调用立即q回Q此Ӟerrno=ENOMSG
  • IPC_EXCEPT 与msgtyp>0配合使用Q返回队列中W一个类型不为msgtyp的消?
  • IPC_NOERROR 如果队列中满x件的消息内容大于所h的msgsz字节Q则把该消息截断Q截断部分将丢失?

msgrcv手册中详l给Z消息cd取不同值时(>0; <0; =0)Q调用将q回消息队列中的哪个消息?/p>

msgrcv()解除d的条件有三个Q?/p>

  1. 消息队列中有了满x件的消息Q?
  2. msqid代表的消息队列被删除Q?
  3. 调用msgrcvQ)的进E被信号中断Q?

调用q回Q?/b>成功q回d消息的实际字节数Q否则返?1?

3Qint msgsnd(int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
向msgid代表的消息队列发送一个消息,卛_发送的消息存储在msgp指向的msgbufl构中,消息的大由msgze指定?

对发送消息来_有意义的msgflg标志为IPC_NOWAITQ指明在消息队列没有_I间容纳要发送的消息Ӟmsgsnd是否{待。造成msgsnd(){待的条件有两种Q?/p>

  • 当前消息的大与当前消息队列中的字节C和超q了消息队列的d量;
  • 当前消息队列的消息数Q单??Q不于消息队列的d量(单位"字节?Q,此时Q虽然消息队列中的消息数目很多,但基本上都只有一个字节?

msgsnd()解除d的条件有三个Q?
  1. 不满上qC个条Ӟx息队列中有容U消息的空_
  2. msqid代表的消息队列被删除Q?
  3. 调用msgsndQ)的进E被信号中断Q?

调用q回Q?/b>成功q回0Q否则返?1?

4Qint msgctl(int msqid, int cmd, struct msqid_ds *buf);
该系l调用对由msqid标识的消息队列执行cmd操作Q共有三Ucmd操作QIPC_STAT、IPC_SET 、IPC_RMID?

  1. IPC_STATQ该命o用来获取消息队列信息Q返回的信息存贮在buf指向的msqidl构中;
  2. IPC_SETQ该命o用来讄消息队列的属性,要设|的属性存储在buf指向的msqidl构中;可设|属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytesQ同Ӟ也媄响msg_ctime成员?
  3. IPC_RMIDQ删除msqid标识的消息队列;

调用q回Q?/b>成功q回0Q否则返?1?





回页?/font>


三、消息队列的限制

每个消息队列的容量(所能容U的字节敎ͼ都有限制Q该值因pȝ不同而不同。在后面的应用实例中Q输Zredhat 8.0的限Ӟl果参见 附录 3?

另一个限制是每个消息队列所能容U的最大消息数Q在redhad 8.0中,该限制是受消息队列容量制U的Q消息个数要于消息队列的容量(字节敎ͼ?/p>

注:上述两个限制是针Ҏ个消息队列而言的,pȝҎ息队列的限制q有pȝ范围内的最大消息队列个敎ͼ以及整个pȝ范围内的最大消息数。一般来_实际开发过E中不会过q个限制?/p>



回页?/font>


四、消息队列应用实?/span>

消息队列应用相对较简单,下面实例基本上覆盖了Ҏ息队列的所有操作,同时Q程序输出结果有助于加深对前面所讲的某些规则及消息队列限制的理解?/p>
#include <sys/types.h>
#include <sys/msg.h>
#include <unistd.h>
void msg_stat(int,struct msqid_ds );
main()
{
int gflags,sflags,rflags;
key_t key;
int msgid;
int reval;
struct msgsbuf{
        int mtype;
        char mtext[1];
    }msg_sbuf;
struct msgmbuf
    {
    int mtype;
    char mtext[10];
    }msg_rbuf;
struct msqid_ds msg_ginfo,msg_sinfo;
char* msgpath="/unix/msgqueue";
key=ftok(msgpath,'a');
gflags=IPC_CREAT|IPC_EXCL;
msgid=msgget(key,gflags|00666);
if(msgid==-1)
{
    printf("msg create error\n");
    return;
}
//创徏一个消息队列后Q输出消息队列缺省属?
msg_stat(msgid,msg_ginfo);
sflags=IPC_NOWAIT;
msg_sbuf.mtype=10;
msg_sbuf.mtext[0]='a';
reval=msgsnd(msgid,&msg_sbuf,sizeof(msg_sbuf.mtext),sflags);
if(reval==-1)
{
    printf("message send error\n");
}
//发送一个消息后Q输出消息队列属?
msg_stat(msgid,msg_ginfo);
rflags=IPC_NOWAIT|MSG_NOERROR;
reval=msgrcv(msgid,&msg_rbuf,4,10,rflags);
if(reval==-1)
    printf("read msg error\n");
else
    printf("read from msg queue %d bytes\n",reval);
//从消息队列中d消息后,输出消息队列属?
msg_stat(msgid,msg_ginfo);
msg_sinfo.msg_perm.uid=8;//just a try
msg_sinfo.msg_perm.gid=8;//
msg_sinfo.msg_qbytes=16388;
//此处验证用户可以更改消息队列的缺省msg_qbytes
//注意q里讄的值大于缺省?
reval=msgctl(msgid,IPC_SET,&msg_sinfo);
if(reval==-1)
{
    printf("msg set info error\n");
    return;
}
msg_stat(msgid,msg_ginfo);
//验证讄消息队列属?
reval=msgctl(msgid,IPC_RMID,NULL);//删除消息队列
if(reval==-1)
{
    printf("unlink msg queue error\n");
    return;
}
}
void msg_stat(int msgid,struct msqid_ds msg_info)
{
int reval;
sleep(1);//只是Z后面输出旉的方?
reval=msgctl(msgid,IPC_STAT,&msg_info);
if(reval==-1)
{
    printf("get msg info error\n");
    return;
}
printf("\n");
printf("current number of bytes on queue is %d\n",msg_info.msg_cbytes);
printf("number of messages in queue is %d\n",msg_info.msg_qnum);
printf("max number of bytes on queue is %d\n",msg_info.msg_qbytes);
//每个消息队列的容量(字节敎ͼ都有限制MSGMNBQ值的大小因系l而异。在创徏新的消息队列Ӟ//msg_qbytes的缺省值就是MSGMNB
printf("pid of last msgsnd is %d\n",msg_info.msg_lspid);
printf("pid of last msgrcv is %d\n",msg_info.msg_lrpid);
printf("last msgsnd time is %s", ctime(&(msg_info.msg_stime)));
printf("last msgrcv time is %s", ctime(&(msg_info.msg_rtime)));
printf("last change time is %s", ctime(&(msg_info.msg_ctime)));
printf("msg uid is %d\n",msg_info.msg_perm.uid);
printf("msg gid is %d\n",msg_info.msg_perm.gid);
}

E序输出l果?附录 3?




回页?/font>


结Q?/span>

消息队列与管道以及有名管道相比,h更大的灵zL,首先Q它提供有格式字节流Q有利于减少开发h员的工作量;其次Q消息具有类型,在实际应用中Q可作ؓ优先U用。这两点是管道以及有名管道所不能比的。同P消息队列可以在几个进E间复用Q而不这几个q程是否h亲缘关系Q这一点与有名道很相|但消息队列是随内核持l的Q与有名道Q随q程持箋Q相比,生命力更强,应用I间更大?/p>

附录 1Q?在参考文献[1]中,l出了IPC随进E持l、随内核持箋以及随文件系l持l的定义Q?

  1. 随进E持l:IPC一直存在到打开IPC对象的最后一个进E关闭该对象为止。如道和有名管道;
  2. 随内核持l:IPC一直持l到内核重新自D或者显C删除该对象为止。如消息队列、信L以及׃n内存{;
  3. 随文件系l持l:IPC一直持l到昄删除该对象ؓ止?

附录 2Q?
l构msg_queue用来描述消息队列_存在于系l空_

struct msg_queue {
    struct kern_ipc_perm q_perm;
    time_t q_stime;         /* last msgsnd time */
    time_t q_rtime;         /* last msgrcv time */
    time_t q_ctime;         /* last change time */
    unsigned long q_cbytes;     /* current number of bytes on queue */
    unsigned long q_qnum;       /* number of messages in queue */
    unsigned long q_qbytes;     /* max number of bytes on queue */
    pid_t q_lspid;          /* pid of last msgsnd */
    pid_t q_lrpid;          /* last receive pid */
    struct list_head q_messages;
    struct list_head q_receivers;
    struct list_head q_senders;
};


l构msqid_ds用来讄或返回消息队列的信息Q存在于用户I间Q?/p>
struct msqid_ds {
    struct ipc_perm msg_perm;
    struct msg *msg_first;      /* first message on queue,unused  */
    struct msg *msg_last;       /* last message in queue,unused */
    __kernel_time_t msg_stime;  /* last msgsnd time */
    __kernel_time_t msg_rtime;  /* last msgrcv time */
    __kernel_time_t msg_ctime;  /* last change time */
    unsigned long  msg_lcbytes; /* Reuse junk fields for 32 bit */
    unsigned long  msg_lqbytes; /* ditto */
    unsigned short msg_cbytes;  /* current number of bytes on queue */
    unsigned short msg_qnum;    /* number of messages in queue */
    unsigned short msg_qbytes;  /* max number of bytes on queue */
    __kernel_ipc_pid_t msg_lspid;   /* pid of last msgsnd */
    __kernel_ipc_pid_t msg_lrpid;   /* last receive pid */
};

//可以看出上述两个l构很相伹{?

附录 3Q?消息队列实例输出l果Q?

current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16384
pid of last msgsnd is 0
pid of last msgrcv is 0
last msgsnd time is Thu Jan  1 08:00:00 1970
last msgrcv time is Thu Jan  1 08:00:00 1970
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
//上面刚刚创徏一个新消息队列时的输出
current number of bytes on queue is 1
number of messages in queue is 1
max number of bytes on queue is 16384
pid of last msgsnd is 2510
pid of last msgrcv is 0
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Thu Jan  1 08:00:00 1970
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
read from msg queue 1 bytes
//实际d的字节数
current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16384   //每个消息队列最大容量(字节敎ͼ
pid of last msgsnd is 2510
pid of last msgrcv is 2510
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Sun Dec 29 18:28:22 2002
last change time is Sun Dec 29 18:28:20 2002
msg uid is 0
msg gid is 0
current number of bytes on queue is 0
number of messages in queue is 0
max number of bytes on queue is 16388   //可看U用户可修改消息队列最大容?
pid of last msgsnd is 2510
pid of last msgrcv is 2510  //Ҏ作消息队列进E的跟踪
last msgsnd time is Sun Dec 29 18:28:21 2002
last msgrcv time is Sun Dec 29 18:28:22 2002
last change time is Sun Dec 29 18:28:23 2002    //msgctl()调用对msg_ctime有媄?
msg uid is 8
msg gid is 8



参考资?

  • UNIX|络~程W二Pq程间通信Q作者:W.Richard StevensQ译者:杨张,清华大学出版C。对POSIX以及pȝV消息队列都有阐述Q对Linux环境下的E序开发有极大的启发意义?br />
  • linux内核源代码情景分析(上)Q毛h、胡希明著,江大学出版C,l出了系lV消息队列相关的源代码分析?br />
  • http://www.fanqiang.com/a4/b2/20010508/113315.htmlQ主要阐qlinux下对文g的操作,详细介绍了对文g的存取权限位Q对IPC对象的存取权限同样具有很好的借鉴意义?

  • msgget、msgsnd、msgrcv、msgctl手册


qL~@@~ 2007-04-03 23:55 发表评论
]]>
[转]Linux环境q程间通信Q二Q~~~~~~~信号http://www.aygfsteel.com/lusm/archive/2007/04/03/108292.htmlqL~@@~qL~@@~Tue, 03 Apr 2007 15:53:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/04/03/108292.htmlhttp://www.aygfsteel.com/lusm/comments/108292.htmlhttp://www.aygfsteel.com/lusm/archive/2007/04/03/108292.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/108292.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/108292.html信号机制q远比想象的复杂Q本文力争用最短的幅Q对该机制做了深入细致的分析。读者可以先M下信号应用实例(在信P下)中)Q这样可以对信号发送直到相应的处理函数执行完毕q一q程有个大致的印象。本文尽量给Z较新函数的应用实例,着重说明这些的功能?/p>

一、信号及信号来源

信号本质

信号是在软g层次上对中断机制的一U模拟,在原理上Q一个进E收C个信号与处理器收C个中断请求可以说是一L。信h异步的,一个进E不必通过M操作来等待信L到达Q事实上Q进E也不知道信号到底什么时候到达?/p>

信号是进E间通信机制中唯一的异步通信机制Q可以看作是异步通知Q通知接收信号的进E有哪些事情发生了。信h制经qPOSIX实时扩展后,功能更加强大Q除了基本通知功能外,q可以传递附加信息?/p>

信号来源

信号事g的发生有两个来源Q硬件来?比如我们按下了键盘或者其它硬件故?QY件来源,最常用发送信Lpȝ函数是kill, raise, alarm和setitimer以及sigqueue函数QY件来源还包括一些非法运等操作?/p>



回页?/font>


二、信LU类

可以从两个不同的分类角度对信可行分c:Q?Q可靠性方面:可靠信号与不可靠信号Q(2Q与旉的关pMQ实时信号与非实时信受在《Linux环境q程间通信Q一Q:道及有名管道》的?中列Zpȝ所支持的所有信受?/p>

1、可靠信号与不可靠信?/font>

"不可靠信?

Linux信号机制基本上是从Unixpȝ中承过来的。早期Unixpȝ中的信号机制比较单和原始Q后来在实践中暴露出一些问题,因此Q把那些建立在早期机制上的信号叫?不可靠信?Q信号值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32QSIGRTMAX=63)的信号都是不可靠信号。这是"不可靠信?的来源。它的主要问题是Q?/p>

  • q程每次处理信号后,将对信L响应讄为默认动作。在某些情况下,导致对信号的错误处理;因此Q用户如果不希望q样的操作,那么p在信号处理函数结ֆ一ơ调用signal()Q重新安装该信号?
  • 信号可能丢失Q后面将Ҏ详细阐述?
    因此Q早期unix下的不可靠信号主要指的是q程可能对信号做出错误的反应以及信号可能丢失?

Linux支持不可靠信P但是对不可靠信号机制做了改进Q在调用完信号处理函数后Q不必重新调用该信号的安装函敎ͼ信号安装函数是在可靠机制上的实现Q。因此,Linux下的不可靠信号问题主要指的是信号可能丢失?/p>

"可靠信号"

随着旉的发展,实践证明了有必要对信L原始机制加以改进和扩充。所以,后来出现的各UUnix版本分别在这斚wq行了研IӞ力图实现"可靠信号"。由于原来定义的信号已有许多应用Q不好再做改动,最l只好又新增加了一些信Pq在一开始就把它们定义ؓ可靠信号Q这些信h持排队,不会丢失。同Ӟ信号的发送和安装也出C新版本:信号发送函数sigqueue()及信号安装函数sigaction()。POSIX.4对可靠信h制做了标准化。但是,POSIX只对可靠信号机制应具有的功能以及信号机制的对外接口做了标准化Q对信号机制的实现没有作具体的规定?/p>

信号g于SIGRTMIN和SIGRTMAX之间的信号都是可靠信P可靠信号克服了信号可能丢q问题。Linux在支持新版本的信号安装函数sigationQ)以及信号发送函数sigqueue()的同Ӟ仍然支持早期的signalQ)信号安装函数Q支持信号发送函数kill()?/p>

注:不要有这L误解Q由sigqueue()发送、sigaction安装的信号就是可靠的。事实上Q可靠信h指后来添加的CP信号g于SIGRTMIN及SIGRTMAX之间Q;不可靠信h信号值小于SIGRTMIN的信受信L可靠与不可靠只与信号值有养I与信L发送及安装函数无关。目前linux中的signal()是通过sigation()函数实现的,因此Q即佉K过signalQ)安装的信P在信号处理函数的l尾也不必再调用一ơ信号安装函数。同Ӟ由signal()安装的实时信h持排队,同样不会丢失?/p>

对于目前linux的两个信号安装函?signal()及sigaction()来说Q它们都不能把SIGRTMIN以前的信号变成可靠信P都不支持排队Q仍有可能丢失,仍然是不可靠信号Q,而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,l过sigaction安装的信号都能传递信息给信号处理函数Q对所有信可一炚w成立Q,而经qsignal安装的信号却不能向信号处理函C递信息。对于信号发送函数来说也是一L?/p>

2、实时信号与非实时信?/font>

早期Unixpȝ只定义了32U信PRet hat7.2支持64U信P~号0-63(SIGRTMIN=31QSIGRTMAX=63)Q将来可能进一步增加,q需要得到内核的支持。前32U信号已l有了预定义|每个信号有了定的用途及含义Qƈ且每U信号都有各自的~省动作。如按键盘的CTRL ^CӞ会生SIGINT信号Q对该信L默认反应是q程l止。后32个信可C实时信P{同于前面阐q的可靠信号。这保证了发送的多个实时信号都被接收。实时信hPOSIX标准的一部分Q可用于应用q程?/p>

非实时信号都不支持排队,都是不可靠信P实时信号都支持排队,都是可靠信号?/p>



回页?/font>


三、进E对信号的响?/span>

q程可以通过三种方式来响应一个信PQ?Q忽略信P卛_信号不做M处理Q其中,有两个信号不能忽略:SIGKILL及SIGSTOPQ(2Q捕捉信受定义信号处理函敎ͼ当信号发生时Q执行相应的处理函数Q(3Q执行缺省操作,LinuxҎU信号都规定了默认操作,详细情况请参考[2]以及其它资料。注意,q程对实时信L~省反应是进E终止?/p>

LinuxI竟采用上述三种方式的哪一个来响应信号Q取决于传递给相应API函数的参数?/p>



回页?/font>


四、信L发?/span>

发送信L主要函数有:kill()、raise()?sigqueue()、alarm()、setitimer()以及abort()?/p>

1、kill()
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid,int signo)

参数pid的?/td> 信号的接收进E?/td>
pid>0 q程ID为pid的进E?/td>
pid=0 同一个进E组的进E?/td>
pid<0 pid!=-1 q程lID?-pid的所有进E?/td>
pid=-1 除发送进E自w外Q所有进EID大于1的进E?/td>

Sinno是信号|当ؓ0Ӟ即空信号Q,实际不发送Q何信P但照常进行错误检查,因此Q可用于查目标进E是否存在,以及当前q程是否h向目标发送信L权限Qroot权限的进E可以向Mq程发送信P非root权限的进E只能向属于同一个session或者同一个用Lq程发送信P?/p>

Kill()最常用于pid>0时的信号发送,调用成功q回 0Q?否则Q返?-1。注Q对于pid<0时的情况Q对于哪些进E将接受信号Q各U版本说法不一Q其实很单,参阅内核源码kernal/signal.c卛_Q上表中的规则是参考red hat 7.2?/p>

2、raiseQ)
#include <signal.h>
int raise(int signo)
向进E本w发送信P参数为即发送的信号倹{调用成功返?0Q否则,q回 -1?

3、sigqueueQ)
#include <sys/types.h>
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval val)
调用成功q回 0Q否则,q回 -1?

sigqueue()是比较新的发送信Ll调用,主要是针对实时信h出的Q当然也支持?2U)Q支持信号带有参敎ͼ与函数sigaction()配合使用?/p>

sigqueue的第一个参数是指定接收信号的进EIDQ第二个参数定卛_发送的信号Q第三个参数是一个联合数据结构union sigvalQ指定了信号传递的参数Q即通常所说的4字节倹{?/p>
 	typedef union sigval {
 		int  sival_int;
 		void *sival_ptr;
 	}sigval_t;

sigqueue()比kill()传递了更多的附加信息,但sigqueue()只能向一个进E发送信P而不能发送信L一个进E组。如果signo=0Q将会执行错误检查,但实际上不发送Q何信P0g号可用于查pid的有效性以及当前进E是否有权限向目标进E发送信受?/p>

在调用sigqueueӞsigval_t指定的信息会拯?参数信号处理函数Q?参数信号处理函数指的是信号处理函数由sigaction安装Qƈ讑֮了sa_sigaction指针Q稍后将阐述Q的siginfo_tl构中,q样信号处理函数可以处理这些信息了。由于sigqueuepȝ调用支持发送带参数信号Q所以比kill()pȝ调用的功能要灉|和强大得多?/p>

注:sigqueueQ)发送非实时信号ӞW三个参数包含的信息仍然能够传递给信号处理函数Q?sigqueueQ)发送非实时信号Ӟ仍然不支持排队,卛_信号处理函数执行q程中到来的所有相同信P都被合ƈZ个信受?/p>

4、alarmQ)
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
专门为SIGALRM信号而设Q在指定的时间secondsU后Q将向进E本w发送SIGALRM信号Q又UCؓ闚w旉。进E调用alarm后,M以前的alarm()调用都将无效。如果参数seconds为零Q那么进E内不再包含Q何闹钟时间?
q回|如果调用alarmQ)前,q程中已l设|了闚w旉Q则q回上一个闹钟时间的剩余旉Q否则返??

5、setitimerQ)
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
setitimer()比alarm功能强大Q支?U类型的定时器:

  • ITIMER_REALQ?讑֮l对旉Q经q指定的旉后,内核发送SIGALRM信号l本q程Q?
  • ITIMER_VIRTUAL 讑֮E序执行旉Q经q指定的旉后,内核发送SIGVTALRM信号l本q程Q?
  • ITIMER_PROF 讑֮q程执行以及内核因本q程而消耗的旉和,l过指定的时间后Q内核将发送ITIMER_VIRTUAL信号l本q程Q?

Setitimer()W一个参数which指定定时器类型(上面三种之一Q;W二个参数是l构itimerval的一个实例,l构itimerval形式见附?。第三个参数可不做处理?/p>

Setitimer()调用成功q回0Q否则返?1?/p>

6、abort()
#include <stdlib.h>
void abort(void);

向进E发送SIGABORT信号Q默认情况下q程会异帔R出,当然可定义自q信号处理函数。即使SIGABORT被进E设|ؓd信号Q调用abort()后,SIGABORT仍然能被q程接收。该函数无返回倹{?/p>



回页?/font>


五、信L安装Q设|信号关联动作)

如果q程要处理某一信号Q那么就要在q程中安装该信号。安装信号主要用来确定信号值及q程针对该信号值的动作之间的映关p,卌E将要处理哪个信P该信可传递给q程Ӟ执行何U操作?/p>

linux主要有两个函数实CL安装Qsignal()、sigaction()。其中signal()在可靠信Ll调用的基础上实? 是库函数。它只有两个参数Q不支持信号传递信息,主要是用于前32U非实时信号的安装;而sigaction()是较新的函数Q由两个pȝ调用实现Qsys_signal以及sys_rt_sigactionQ,有三个参敎ͼ支持信号传递信息,主要用来?sigqueue() pȝ调用配合使用Q当Ӟsigaction()同样支持非实时信L安装。sigaction()优于signal()主要体现在支持信号带有参数?/p>

1、signal()
#include <signal.h>
void (*signal(int signum, void (*handler))(int)))(int);
如果该函数原型不Ҏ理解的话Q可以参考下面的分解方式来理解:
typedef void (*sighandler_t)(int)Q?
sighandler_t signal(int signum, sighandler_t handler));
W一个参数指定信L|W二个参数指定针对前面信号值的处理Q可以忽略该信号Q参数设为SIG_IGNQ;可以采用pȝ默认方式处理信号(参数设ؓSIG_DFL)Q也可以自己实现处理方式(参数指定一个函数地址)?
如果signal()调用成功Q返回最后一ơؓ安装信号signum而调用signal()时的handler|p|则返回SIG_ERR?

2、sigaction()
#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

sigaction函数用于改变q程接收到特定信号后的行为。该函数的第一个参Cؓ信号的|可以为除SIGKILL及SIGSTOP外的M一个特定有效的信号Qؓq两个信号定义自q处理函数Q将D信号安装错误Q。第二个参数是指向结构sigaction的一个实例的指针Q在l构sigaction的实例中Q指定了对特定信L处理Q可以ؓI,q程会以~省方式对信号处理;W三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。如果把W二、第三个参数都设为NULLQ那么该函数可用于检查信L有效性?/p>

W二个参数最为重要,其中包含了对指定信号的处理、信h传递的信息、信号处理函数执行过E中应屏蔽掉哪些函数{等?/p>

sigactionl构定义如下Q?/p>
	struct sigaction {
					union{
						__sighandler_t _sa_handler;
						void (*_sa_sigaction)(int,struct siginfo *, void *)Q?
						}_u
                   	sigset_t sa_maskQ?
                  	unsigned long sa_flagsQ?
    	          	void (*sa_restorer)(void)Q?
        	      	}
					

其中Qsa_restorerQ已q时QPOSIX不支持它Q不应再被用?/p>

1、联合数据结构中的两个元素_sa_handler以及*_sa_sigaction指定信号兌函数Q即用户指定的信号处理函数。除了可以是用户自定义的处理函数外,q可以ؓSIG_DFL(采用~省的处理方?Q也可以为SIG_IGNQ忽略信P?/p>

2、由_sa_handler指定的处理函数只有一个参敎ͼ即信号|所以信号不能传递除信号g外的M信息Q由_sa_sigaction是指定的信号处理函数带有三个参数Q是为实时信可设的(当然同样支持非实时信PQ它指定一?参数信号处理函数。第一个参Cؓ信号|W三个参数没有用(posix没有规范使用该参数的标准Q,W二个参数是指向siginfo_tl构的指针,l构中包含信h带的数据|参数所指向的结构如下:

siginfo_t {
                  int      si_signo;  /* 信号|Ҏ有信h意义*/
                  int      si_errno;  /* errno|Ҏ有信h意义*/
                  int      si_code;   /* 信号产生的原因,Ҏ有信h意义*/
				union{				  /* 联合数据l构Q不同成员适应不同信号 */	
					//保分配_大的存储I间
					int _pad[SI_PAD_SIZE];
					//对SIGKILL有意义的l构
					struct{
							...
						  }...
						... ...
						... ...					
					//对SIGILL, SIGFPE, SIGSEGV, SIGBUS有意义的l构
      				struct{
							...
						  }...
						... ...
					  }
			}
			

注:Z更便于阅读,在说明问题时常把该结构表CZؓ附录2所表示的Ş式?/p>

siginfo_tl构中的联合数据成员保该结构适应所有的信号Q比如对于实时信h_则实际采用下面的l构形式Q?/p>
	typedef struct {
		int si_signo;
		int si_errno;			
		int si_code;			
		union sigval si_value;	
		} siginfo_t;
		

l构的第四个域同样ؓ一个联合数据结构:

	union sigval {
		int sival_int;		
		void *sival_ptr;	
		}

采用联合数据l构Q说明siginfo_tl构中的si_value要么持有一?字节的整数|要么持有一个指针,q就构成了与信号相关的数据。在信号的处理函CQ包含这L信号相关数据指针Q但没有规定具体如何对这些数据进行操作,操作Ҏ应该q序开发h员根据具体Q务事先约定?/p>

前面在讨论系l调用sigqueue发送信hQsigqueue的第三个参数是sigval联合数据l构Q当调用sigqueueӞ该数据结构中的数据就拷贝到信号处理函数的第二个参数中。这P在发送信号同Ӟ可以让信号传递一些附加信息。信号可以传递信息对E序开发是非常有意义的?/p>

信号参数的传递过E可囄如下Q?/p>


3、sa_mask指定在信号处理程序执行过E中Q哪些信号应当被d。缺省情况下当前信号本n被阻塞,防止信号的嵌套发送,除非指定SA_NODEFER或者SA_NOMASK标志位?/p>

注:h意sa_mask指定的信号阻塞的前提条gQ是在由sigactionQ)安装信号的处理函数执行过E中由sa_mask指定的信h被阻塞?/p>

4、sa_flags中包含了许多标志位,包括刚刚提到的SA_NODEFER及SA_NOMASK标志位。另一个比较重要的标志位是SA_SIGINFOQ当讑֮了该标志位时Q表CZ号附带的参数可以被传递到信号处理函数中,因此Q应该ؓsigactionl构中的sa_sigaction指定处理函数Q而不应该为sa_handler指定信号处理函数Q否则,讄该标志变得毫无意义。即使ؓsa_sigaction指定了信号处理函敎ͼ如果不设|SA_SIGINFOQ信号处理函数同样不能得C号传递过来的数据Q在信号处理函数中对q些信息的访问都导致段错误QSegmentation faultQ?/p>

注:很多文献在阐q该标志位时都认为,如果讄了该标志位,必d义三参数信号处理函数。实际不是这LQ验证方法很单:自己实现一个单一参数信号处理函数Qƈ在程序中讄该标志位Q可以察看程序的q行l果。实际上Q可以把该标志位看成信号是否传递参数的开养I如果讄该位Q则传递参敎ͼ否则Q不传递参数?/p>



回页?/font>


六、信号集及信号集操作函数Q?/span>

信号集被定义ZU数据类型:

	typedef struct {
			unsigned long sig[_NSIG_WORDS]Q?
			} sigset_t

信号集用来描qCL集合Qlinux所支持的所有信号可以全部或部分的出现在信号集中Q主要与信号d相关函数配合使用。下面是Z号集操作定义的相兛_敎ͼ

	#include <signal.h>
int sigemptyset(sigset_t *set)Q?
int sigfillset(sigset_t *set)Q?
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum)Q?
int sigismember(const sigset_t *set, int signum)Q?
sigemptyset(sigset_t *set)初始化由set指定的信号集Q信号集里面的所有信可清空Q?
sigfillset(sigset_t *set)调用该函数后Qset指向的信号集中将包含linux支持?4U信P
sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号Q?
sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号Q?
sigismember(const sigset_t *set, int signum)判定信号signum是否在set指向的信号集中?





回页?/font>


七、信号阻塞与信号未决:

每个q程都有一个用来描q哪些信号递送到q程时将被阻塞的信号集,该信号集中的所有信号在递送到q程后都被d。下面是与信号阻塞相关的几个函数Q?/p>
#include <signal.h>
int  sigprocmask(int  how,  const  sigset_t *set, sigset_t *oldset))Q?
int sigpending(sigset_t *set));
int sigsuspend(const sigset_t *mask))Q?

sigprocmask()函数能够Ҏ参数how来实现对信号集的操作Q操作主要有三种Q?/p>
参数how q程当前信号?/td>
SIG_BLOCK 在进E当前阻塞信号集中添加set指向信号集中的信?/td>
SIG_UNBLOCK 如果q程d信号集中包含set指向信号集中的信P则解除对该信Ld
SIG_SETMASK 更新q程d信号集ؓset指向的信号集

sigpending(sigset_t *set))获得当前已递送到q程Q却被阻塞的所有信P在set指向的信号集中返回结果?/p>

sigsuspend(const sigset_t *mask))用于在接收到某个信号之前, 临时用mask替换q程的信h? q暂停进E执行,直到收到信号为止。sigsuspend q回后将恢复调用之前的信h码。信号处理函数完成后Q进E将l箋执行。该pȝ调用始终q回-1Qƈerrno讄为EINTR?/p>

附录1Q结构itimervalQ?/p>
            struct itimerval {
                struct timeval it_interval; /* next value */
                struct timeval it_value;    /* current value */
            };
            struct timeval {
                long tv_sec;                /* seconds */
                long tv_usec;               /* microseconds */
            };

附录2Q三参数信号处理函数中第二个参数的说明性描qͼ

siginfo_t {
int      si_signo;  /* 信号|Ҏ有信h意义*/
int      si_errno;  /* errno|Ҏ有信h意义*/
int      si_code;   /* 信号产生的原因,Ҏ有信h意义*/
pid_t    si_pid;    /* 发送信Lq程ID,对kill(2),实时信号以及SIGCHLD有意?*/
uid_t    si_uid;    /* 发送信可E的真实用户IDQ对kill(2),实时信号以及SIGCHLD有意?*/
int      si_status; /* 退出状态,对SIGCHLD有意?/
clock_t  si_utime;  /* 用户消耗的旉Q对SIGCHLD有意?*/
clock_t  si_stime;  /* 内核消耗的旉Q对SIGCHLD有意?*/
sigval_t si_value;  /* 信号|Ҏ有实时有意义Q是一个联合数据结构,可以Z个整敎ͼ由si_int标示Q也可以Z个指针,由si_ptr标示Q?/
	
void *   si_addr;   /* 触发fault的内存地址Q对SIGILL,SIGFPE,SIGSEGV,SIGBUS 信号有意?/
int      si_band;   /* 对SIGPOLL信号有意?*/
int      si_fd;     /* 对SIGPOLL信号有意?*/
}

实际上,除了前三个元素外Q其他元素组l在一个联合结构中Q在联合数据l构中,又根据不同的信号l织成不同的l构。注释中提到的对某种信号有意义指的是Q在该信L处理函数中可以访问这些域来获得与信号相关的有意义的信息,只不q特定信号只对特定信息感兴趣而已?br />

在信P上)中,讨论了linux信号U类、来源、如何安装一个信号以及对信号集的操作。本部分则首先讨Z信号的生命周期上认识信号Q或者宏观上看似单的信号机制Q进E收C号后Q作相应的处理,看上d单不q了Q,在微观上I竟是如何实现的Q也是在更深层次上理解信受接下来q讨Z信号~程的一些注意事,最后给Z信号~程的一些实例?/blockquote>

一、信L命周?/span>

从信号发送到信号处理函数的执行完?/p>

对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完?来说Q可以分Z个重要的阶段Q这三个阶段由四个重要事件来ȝQ信可生;信号在进E中注册完毕Q信号在q程中的注销完毕Q信号处理函数执行完毕。相M个事件的旉间隔构成信号生命周期的一个阶Dc?/p>




下面阐述四个事g的实际意义:

  1. 信号"诞生"。信L诞生指的是触发信L事g发生Q如到g异常、定时器时以及调用信号发送函数kill()或sigqueue(){)?
  2. 信号在目标进E中"注册"Q进E的task_structl构中有关于本进E中未决信号的数据成员:
    struct sigpending pendingQ?
    struct sigpending{
    	struct sigqueue *head, **tail;
    	sigset_t signal;
    };
    

    W三个成员是q程中所有未决信号集Q第一、第二个成员分别指向一个sigqueuecd的结构链Q称之ؓ"未决信号信息?Q的首尾Q信息链中的每个sigqueuel构ȝ一个特定信h携带的信息,q指向下一个sigqueuel构:
    struct sigqueue{
    	struct sigqueue *next;
    	siginfo_t info;
    }
    

    信号在进E中注册指的是信号值加入到q程的未决信号集中(sigpendingl构的第二个成员sigset_t signalQ,q且信号所携带的信息被保留到未决信号信息链的某个sigqueuel构中。只要信号在q程的未决信号集中,表明q程已经知道q些信号的存在,但还没来得及处理Q或者该信号被进E阻塞?

    注:
    当一个实时信号发送给一个进E时Q不该信号是否已经在进E中注册Q都会被再注册一ơ,因此Q信号不会丢失,因此Q实时信号又叫做"可靠信号"。这意味着同一个实时信号可以在同一个进E的未决信号信息链中占有多个sigqueuel构Q进E每收到一个实时信P都会为它分配一个结构来登记该信号信息,q把该结构添加在未决信号铑ְQ即所有诞生的实时信号都会在目标进E中注册Q;
    当一个非实时信号发送给一个进E时Q如果该信号已经在进E中注册Q则该信号将被丢弃,造成信号丢失。因此,非实时信号又叫做"不可靠信?。这意味着同一个非实时信号在进E的未决信号信息链中Q至多占有一个sigqueuel构Q一个非实时信号诞生后,Q?Q、如果发现相同的信号已经在目标结构中注册Q则不再注册Q对于进E来_相当于不知道本次信号发生Q信号丢失;Q?Q、如果进E的未决信号中没有相同信P则在q程中注册自己)?

  3. 信号在进E中的注销。在目标q程执行q程中,会检是否有信号{待处理Q每ơ从pȝI间q回到用L间时都做q样的检查)。如果存在未决信L待处理且该信h有被q程dQ则在运行相应的信号处理函数前,q程会把信号在未决信号链中占有的l构卸掉。是否将信号从进E未决信号集中删除对于实时与非实时信h不同的。对于非实时信号来说Q由于在未决信号信息链中最多只占用一个sigqueuel构Q因此该l构被释攑֐Q应该把信号在进E未决信号集中删除(信号注销完毕Q;而对于实时信h_可能在未决信号信息链中占用多个sigqueuel构Q因此应该针对占用sigqueuel构的数目区别对待:如果只占用一个sigqueuel构Q进E只收到该信号一ơ)Q则应该把信号在q程的未决信号集中删除(信号注销完毕Q。否则,不应该在q程的未决信号集中删除该信号Q信h销完毕Q?
    q程在执行信L应处理函C前,首先要把信号在进E中注销?
  4. 信号生命l止。进E注销信号后,立即执行相应的信号处理函敎ͼ执行完毕后,信号的本ơ发送对q程的媄响彻底结束?

    注:
    1Q信h册与否,与发送信L函数Q如kill()或sigqueue(){)以及信号安装函数Qsignal()及sigaction()Q无养I只与信号值有养I信号值小于SIGRTMIN的信h多只注册一ơ,信号值在SIGRTMIN及SIGRTMAX之间的信P只要被进E接收到p注册Q?
    2Q在信号被注销到相应的信号处理函数执行完毕q段旉内,如果q程又收到同一信号多次Q则对实时信h_每一ơ都会在q程中注册;而对于非实时信号来说Q无论收到多次信号Q都会视为只收到一个信P只在q程中注册一ơ?





回页?/font>


二、信LE注意事?/span>

  1. 防止不该丢失的信号丢失。如果对八中所提到的信L命周期理解深ȝ话,很容易知道信号会不会丢失Q以及在哪里丢失?
  2. E序的可UL?/b>
    考虑到程序的可移植性,应该量采用POSIX信号函数QPOSIX信号函数主要分ؓ两类Q?
    • POSIX 1003.1信号函数Q?Kill()、sigaction()、sigaddset()、sigdelset()、sigemptyset()、sigfillset()、sigismember()、sigpending()、sigprocmask()、sigsuspend()?
    • POSIX 1003.1b信号函数。POSIX 1003.1b在信L实时性方面对POSIX 1003.1做了扩展Q包括以下三个函敎ͼ sigqueue()、sigtimedwait()、sigwaitinfo()。其中,sigqueue主要针对信号发送,而sigtimedwait及sigwaitinfo()主要用于取代sigsuspend()函数Q后面有相应实例?
      #include <signal.h>
      int sigwaitinfo(sigset_t *set, siginfo_t *info).
      

      该函Csigsuspend()cMQ阻塞一个进E直到特定信号发生,但信号到来时不执行信号处理函敎ͼ而是q回信号倹{因此ؓ了避免执行相应的信号处理函数Q必d调用该函数前Qɘq程屏蔽掉set指向的信P因此调用该函数的典型代码是:
      sigset_t newmask;
      int rcvd_sig; 
      siginfo_t info;
      sigemptyset(&newmask);
      sigaddset(&newmask, SIGRTMIN);
      sigprocmask(SIG_BLOCK, &newmask, NULL);
      rcvd_sig = sigwaitinfo(&newmask, &info) 
      if (rcvd_sig == -1) {
      	..
      }
      

      调用成功q回信号|否则q回-1。sigtimedwait()功能怼Q只不过增加了一个进E等待的旉?
  3. E序的稳定性?/b>
    Z增强E序的稳定性,在信号处理函C应用可重入函数?

    信号处理E序中应当用可再入Q可重入Q函敎ͼ注:所谓可重入函数是指一个可以被多个d调用的过E,d在调用时不必担心数据是否会出错)。因E在收到信号后,将跌{C号处理函数去接着执行。如果信号处理函C使用了不可重入函敎ͼ那么信号处理函数可能会修改原来进E中不应该被修改的数据,q样q程从信号处理函Cq回接着执行Ӟ可能会出C可预料的后果。不可再入函数在信号处理函数中被视ؓ不安全函数?/p>

    满下列条g的函数多数是不可再入的:Q?Q用静态的数据l构Q如getlogin()Qgmtime()Qgetgrgid()Qgetgrnam()Qgetpwuid()以及getpwnam(){等Q(2Q函数实现时Q调用了mallocQ)或者free()函数Q(3Q实现时使用了标准I/O函数的。The Open Group视下列函Cؓ可再入的Q?/p>_exitQ)、accessQ)、alarmQ)、cfgetispeedQ)、cfgetospeedQ)、cfsetispeedQ)、cfsetospeedQ)、chdirQ)、chmodQ)、chownQ)、closeQ)、creatQ)、dupQ)、dup2Q)、execleQ)、execveQ)、fcntlQ)、forkQ)、fpathconfQ)、fstatQ)、fsyncQ)、getegidQ)?geteuidQ)、getgidQ)、getgroupsQ)、getpgrpQ)、getpidQ)、getppidQ)、getuidQ)、killQ)、linkQ)、lseekQ)、mkdirQ)、mkfifoQ)?openQ)、pathconfQ)、pauseQ)、pipeQ)、raiseQ)、readQ)、renameQ)、rmdirQ)、setgidQ)、setpgidQ)、setsidQ)、setuidQ)?sigactionQ)、sigaddsetQ)、sigdelsetQ)、sigemptysetQ)、sigfillsetQ)、sigismemberQ)、signalQ)、sigpendingQ)、sigprocmaskQ)、sigsuspendQ)、sleepQ)、statQ)、sysconfQ)、tcdrainQ)、tcflowQ)、tcflushQ)、tcgetattrQ)、tcgetpgrpQ)、tcsendbreakQ)、tcsetattrQ)、tcsetpgrpQ)、timeQ)、timesQ)?umaskQ)、unameQ)、unlinkQ)、utimeQ)、waitQ)、waitpidQ)、writeQ)?

    即信号处理函数使用的都?安全函数"Q同栯注意q入处理函数Ӟ首先要保存errno的|l束Ӟ再恢复原倹{因为,信号处理q程中,errno值随时可能被改变。另外,longjmp()以及siglongjmp()没有被列为可再入函数Q因Z能保证紧接着两个函数的其它调用是安全的?/p>





回页?/font>


三、深入浅出:信号应用实例

linux下的信号应用q没有想象的那么恐怖,E序员所要做的最多只有三件事情:

  1. 安装信号Q推荐用sigaction()Q;
  2. 实现三参C号处理函敎ͼhandler(int signal,struct siginfo *info, void *)Q?
  3. 发送信P推荐使用sigqueue()?

实际上,Ҏ些信h_只要安装信号p够了Q信号处理方式采用缺省或忽略Q。其他可能要做的无非是与信号集相关的几种操作?/p>

实例一Q信号发送及处理
实现一个信h收程序sigreceiveQ其中信号安装由sigactionQ)Q?

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
	struct sigaction act;	
	int sig;
	sig=atoi(argv[1]);
	
	sigemptyset(&act.sa_mask);
	act.sa_flags=SA_SIGINFO;
	act.sa_sigaction=new_op;
	
	if(sigaction(sig,&act,NULL) < 0)
	{
		printf("install sigal error\n");
	}
	
	while(1)
	{
		sleep(2);
		printf("wait for the signal\n");
	}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
	printf("receive signal %d", signum);
	sleep(5);
}

说明Q命令行参数Z号|后台q行sigreceive signo &Q可获得该进E的IDQ假设ؓpidQ然后再另一l端上运行kill -s signo pid验证信号的发送接收及处理。同Ӟ可验证信L排队问题?
注:可以用sigqueue实现一个命令行信号发送程序sigqueuesendQ见 附录1?

实例二:信号传递附加信?/b>
主要包括两个实例Q?

  1. 向进E本w发送信Pq传递指针参敎ͼ
    #include <signal.h>
    #include <sys/types.h>
    #include <unistd.h>
    void new_op(int,siginfo_t*,void*);
    int main(int argc,char**argv)
    {
    	struct sigaction act;	
    	union sigval mysigval;
    	int i;
    	int sig;
    	pid_t pid;		
    	char data[10];
    	memset(data,0,sizeof(data));
    	for(i=0;i < 5;i++)
    		data[i]='2';
    	mysigval.sival_ptr=data;
    	
    	sig=atoi(argv[1]);
    	pid=getpid();
    	
    	sigemptyset(&act.sa_mask);
    	act.sa_sigaction=new_op;//三参C号处理函?
    	act.sa_flags=SA_SIGINFO;//信息传递开?
    	if(sigaction(sig,&act,NULL) < 0)
    	{
    		printf("install sigal error\n");
    	}
    	while(1)
    	{
    		sleep(2);
    		printf("wait for the signal\n");
    		sigqueue(pid,sig,mysigval);//向本q程发送信Pq传递附加信?
    	}
    }
    void new_op(int signum,siginfo_t *info,void *myact)//三参C号处理函数的实现
    {
    	int i;
    	for(i=0;i<10;i++)
    	{
    		printf("%c\n ",(*( (char*)((*info).si_ptr)+i)));
    	}
    	printf("handle signal %d over;",signum);
    }
    

    q个例子中,信号实现了附加信息的传递,信号I竟如何对这些信息进行处理则取决于具体的应用?/p>

  2. 2?不同q程间传递整型参敎ͼ?中的信号发送和接收攑֜两个E序中,q且在发送过E中传递整型参数?
    信号接收E序Q?
    #include <signal.h>
    #include <sys/types.h>
    #include <unistd.h>
    void new_op(int,siginfo_t*,void*);
    int main(int argc,char**argv)
    {
    	struct sigaction act;
    	int sig;
    	pid_t pid;		
    	
    	pid=getpid();
    	sig=atoi(argv[1]);	
    	
    	sigemptyset(&act.sa_mask);
    	act.sa_sigaction=new_op;
    	act.sa_flags=SA_SIGINFO;
    	if(sigaction(sig,&act,NULL)<0)
    	{
    		printf("install sigal error\n");
    	}
    	while(1)
    	{
    		sleep(2);
    		printf("wait for the signal\n");
    	}
    }
    void new_op(int signum,siginfo_t *info,void *myact)
    {
    	printf("the int value is %d \n",info->si_int);
    }
    

    信号发送程序:命o行第二个参数Z号|W三个参Cؓ接收q程ID?/p>
    #include <signal.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <sys/types.h>
    main(int argc,char**argv)
    {
    	pid_t pid;
    	int signum;
    	union sigval mysigval;
    	signum=atoi(argv[1]);
    	pid=(pid_t)atoi(argv[2]);
    	mysigval.sival_int=8;//不代表具体含义,只用于说明问?
    	if(sigqueue(pid,signum,mysigval)==-1)
    		printf("send error\n");
    	sleep(2);
    }
    

    注:实例2的两个例子侧重点在于用信h传递信息,目前关于在linux下通过信号传递信息的实例非常,倒是Unix下有一些,但传递的基本上都是关于传递一个整敎ͼ传递指针的我还没看到。我一直没有实C同进E间的指针传递(实际上更有意义)Q也许在实现Ҏ上存在问题吧Q请实现者email我?

实例三:信号d及信号集操作

#include "signal.h"
#include "unistd.h"
static void my_op(int);
main()
{
	sigset_t new_mask,old_mask,pending_mask;
	struct sigaction act;
	sigemptyset(&act.sa_mask);
	act.sa_flags=SA_SIGINFO;
	act.sa_sigaction=(void*)my_op;
	if(sigaction(SIGRTMIN+10,&act,NULL))
		printf("install signal SIGRTMIN+10 error\n");
	sigemptyset(&new_mask);
	sigaddset(&new_mask,SIGRTMIN+10);
	if(sigprocmask(SIG_BLOCK, &new_mask,&old_mask))
		printf("block signal SIGRTMIN+10 error\n");
	sleep(10);	
	printf("now begin to get pending mask and unblock SIGRTMIN+10\n");
	if(sigpending(&pending_mask)<0)
		printf("get pending mask error\n");
	if(sigismember(&pending_mask,SIGRTMIN+10))
		printf("signal SIGRTMIN+10 is pending\n");
	if(sigprocmask(SIG_SETMASK,&old_mask,NULL)<0)
		printf("unblock signal error\n");
	printf("signal unblocked\n");
	sleep(10);
}
static void my_op(int signum)
{
	printf("receive signal %d \n",signum);
}

~译该程序,q以后台方式q行。在另一l端向该q程发送信?q行kill -s 42 pidQSIGRTMIN+10?2)Q查看结果可以看出几个关键函数的q行机制Q信号集相关操作比较单?/p>

注:在上面几个实例中Q用了printf()函数Q只是作断工Ppringf()函数是不可重入的Q不应在信号处理函数中用?





回页?/font>


l束语:

pȝ地对linux信号机制q行分析、ȝ使我受益匪浅Q感谢王乐{网友的支持Q?
Comments and suggestions are greatly welcome!





回页?/font>


附录1Q?/span>

用sigqueue实现的命令行信号发送程序sigqueuesendQ命令行W二个参数是发送的信号|W三个参数是接收该信Lq程IDQ可以配合实例一使用Q?/p>

#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char**argv)
{
	pid_t pid;
	int sig;
	sig=atoi(argv[1]);
	pid=atoi(argv[2]);
	sigqueue(pid,sig,NULL);
	sleep(2);
}



参考资?

 

 



qL~@@~ 2007-04-03 23:53 发表评论
]]>[转]Linux环境q程间通信Q一Q~~~~~~~道及有名管?/title><link>http://www.aygfsteel.com/lusm/archive/2007/04/03/108291.html</link><dc:creator>qL~@@~</dc:creator><author>qL~@@~</author><pubDate>Tue, 03 Apr 2007 15:51:00 GMT</pubDate><guid>http://www.aygfsteel.com/lusm/archive/2007/04/03/108291.html</guid><wfw:comment>http://www.aygfsteel.com/lusm/comments/108291.html</wfw:comment><comments>http://www.aygfsteel.com/lusm/archive/2007/04/03/108291.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lusm/comments/commentRss/108291.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lusm/services/trackbacks/108291.html</trackback:ping><description><![CDATA[ <blockquote>在本pd序中作者概qC linux q程间通信的几U主要手Dc其中管道和有名道是最早的q程间通信机制之一Q管道可用于h亲缘关系q程间的通信Q有名管道克服了道没有名字的限Ӟ因此Q除h道所h的功能外Q它q允许无亲缘关系q程间的通信?认清道和有名管道的d规则是在E序中应用它们的关键Q本文在详细讨论了管道和有名道的通信机制的基上,用实例对其读写规则进行了E序验证Q这样做有利于增者对d规则的感性认识,同时也提供了应用范例?/blockquote> <!--START RESERVED FOR FUTURE USE INCLUDE FILES--> <!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!--END RESERVED FOR FUTURE USE INCLUDE FILES--> <p> <a name="N10040"> <span id="wmqeeuq" class="atitle">1?道概述及相关API应用</span> </a> </p> <p> <a name="N10046"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1.1 道相关的关键概?/font> </strong> </span> </a> </p> <p>道是Linux支持的最初Unix IPC形式之一Q具有以下特点:</p> <ul> <li>道是半双工的,数据只能向一个方向流动;需要双斚w信Ӟ需要徏立v两个道Q? </li> <li>只能用于父子q程或者兄弟进E之_h亲缘关系的进E)Q? </li> <li>单独构成一U独立的文gpȝQ管道对于管道两端的q程而言Q就是一个文Ӟ但它不是普通的文gQ它不属于某U文件系l,而是自立门户Q单独构成一U文件系l,q且只存在与内存中? </li> <li>数据的读出和写入Q一个进E向道中写的内容被道另一端的q程d。写入的内容每次都添加在道~冲区的末尾Qƈ且每ơ都是从~冲区的头部d数据?</li> </ul> <p> <a name="N1005E"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1.2道的创建:</font> </strong> </span> </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <unistd.h> int pipe(int fd[2]) </pre> </td> </tr> </tbody> </table> <br /> <p>该函数创建的道的两端处于一个进E中_在实际应用中没有太大意义Q因此,一个进E在由pipe()创徏道后,一般再fork一个子q程Q然后通过道实现父子q程间的通信Q因此也不难推出Q只要两个进E中存在亲缘关系Q这里的亲缘关系指的是具有共同的先Q都可以采用道方式来进行通信Q?/p> <p> <a name="N1006B"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1.3道的读写规则:</font> </strong> </span> </a> </p> <p>道两端可分别用描述字fd[0]以及fd[1]来描qͼ需要注意的是,道的两端是固定了Q务的。即一端只能用于读Q由描述字fd[0]表示Q称其ؓ道ȝQ另一端则只能用于写,由描q字fd[1]来表C,U其为管道写端。如果试图从道写端d数据Q或者向道ȝ写入数据都将D错误发生。一般文件的I/O函数都可以用于管道,如close、read、write{等?/p> <p>从管道中d数据Q?/p> <ul> <li>如果道的写端不存在Q则认ؓ已经d了数据的末尾Q读函数q回的读出字节数?Q? </li> <li>当管道的写端存在Ӟ如果h的字节数目大于PIPE_BUFQ则q回道中现有的数据字节敎ͼ如果h的字节数目不大于PIPE_BUFQ则q回道中现有数据字节数Q此Ӟ道中数据量于h的数据量Q;或者返回请求的字节敎ͼ此时Q管道中数据量不于h的数据量Q。注Q(PIPE_BUF在include/linux/limits.h中定义,不同的内核版本可能会有所不同。Posix.1要求PIPE_BUF臛_?12字节Qred hat 7.2中ؓ4096Q?</li> </ul> <p>关于道的读规则验证Q?/p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode"> /************** * readtest.c * **************/ #include <unistd.h> #include <sys/types.h> #include <errno.h> main() { int pipe_fd[2]; pid_t pid; char r_buf[100]; char w_buf[4]; char* p_wbuf; int r_num; int cmd; memset(r_buf,0,sizeof(r_buf)); memset(w_buf,0,sizeof(r_buf)); p_wbuf=w_buf; if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } if((pid=fork())==0) { printf("\n"); close(pipe_fd[1]); sleep(3);//保父进E关闭写? r_num=read(pipe_fd[0],r_buf,100); printf( "read num is %d the data read from the pipe is %d\n",r_num,atoi(r_buf)); close(pipe_fd[0]); exit(); } else if(pid>0) { close(pipe_fd[0]);//read strcpy(w_buf,"111"); if(write(pipe_fd[1],w_buf,4)!=-1) printf("parent write over\n"); close(pipe_fd[1]);//write printf("parent close fd[1] over\n"); sleep(10); } } /************************************************** * E序输出l果Q? * parent write over * parent close fd[1] over * read num is 4 the data read from the pipe is 111 * 附加l论Q? * 道写端关闭后,写入的数据将一直存在,直到d为止. ****************************************************/ </pre> </td> </tr> </tbody> </table> <br /> <p>向管道中写入数据Q?/p> <ul> <li>向管道中写入数据Ӟlinux不保证写入的原子性,道~冲Z有空闲区域,写进E就会试囑֐道写入数据。如果读q程不读走管道缓冲区中的数据Q那么写操作一直阻塞?<br />注:只有在管道的ȝ存在Ӟ向管道中写入数据才有意义。否则,向管道中写入数据的进E将收到内核传来的SIFPIPE信号Q应用程序可以处理该信号Q也可以忽略Q默认动作则是应用程序终止)?</li> </ul> <p>对管道的写规则的验证1Q写端对ȝ存在的依赖?/p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <unistd.h> #include <sys/types.h> main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char* w_buf; int writenum; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } if((pid=fork())==0) { close(pipe_fd[0]); close(pipe_fd[1]); sleep(10); exit(); } else if(pid>0) { sleep(1); //{待子进E完成关闭读端的操作 close(pipe_fd[0]);//write w_buf="111"; if((writenum=write(pipe_fd[1],w_buf,4))==-1) printf("write to pipe error\n"); else printf("the bytes write to pipe is %d \n", writenum); close(pipe_fd[1]); } } </pre> </td> </tr> </tbody> </table> <br /> <p>则输出结果ؓQ?Broken pipe,原因是该管道以及它的所有fork()产物的读端都已经被关闭。如果在父进E中保留ȝQ即在写完pipe后,再关闭父q程的读端,也会正常写入pipeQ读者可自己验证一下该l论。因此,在向道写入数据Ӟ臛_应该存在某一个进E,其中道ȝ没有被关闭,否则׃出现上述错误Q管道断?q程收到了SIGPIPE信号Q默认动作是q程l止Q?/p> <p>对管道的写规则的验证2Qlinux不保证写道的原子性验?/p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <unistd.h> #include <sys/types.h> #include <errno.h> main(int argc,char**argv) { int pipe_fd[2]; pid_t pid; char r_buf[4096]; char w_buf[4096*2]; int writenum; int rnum; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } if((pid=fork())==0) { close(pipe_fd[1]); while(1) { sleep(1); rnum=read(pipe_fd[0],r_buf,1000); printf("child: readnum is %d\n",rnum); } close(pipe_fd[0]); exit(); } else if(pid>0) { close(pipe_fd[0]);//write memset(r_buf,0,sizeof(r_buf)); if((writenum=write(pipe_fd[1],w_buf,1024))==-1) printf("write to pipe error\n"); else printf("the bytes write to pipe is %d \n", writenum); writenum=write(pipe_fd[1],w_buf,4096); close(pipe_fd[1]); } } 输出l果Q? the bytes write to pipe 1000 the bytes write to pipe 1000 //注意Q此行输明了写入的非原子? the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 1000 the bytes write to pipe 120 //注意Q此行输明了写入的非原子? the bytes write to pipe 0 the bytes write to pipe 0 ...... </pre> </td> </tr> </tbody> </table> <br /> <p>l论Q?/p> <p>写入数目于4096时写入是非原子的Q?<br />如果把父q程中的两次写入字节数都改ؓ5000Q则很容易得Z面结论: <br />写入道的数据量大于4096字节Ӟ~冲区的I闲I间被写入数据Q补齐)Q直到写完所有数据ؓ止,如果没有q程L据,则一直阻塞?</p> <p> <a name="N100AD"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1.4道应用实例Q?/font> </strong> </span> </a> </p> <p> <strong>实例一Q用于shell</strong> </p> <p>道可用于输入输出重定向Q它一个命令的输出直接定向到另一个命令的输入。比如,当在某个shellE序QBourne shell或C shell{)键入who│wc -l后,相应shellE序创建who以及wc两个q程和这两个q程间的道。考虑下面的命令行Q?/p> <p>$kill -l q行l果?<a ><font color="#996699">附一</font></a>?</p> <p>$kill -l | grep SIGRTMIN q行l果如下Q?/p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14 </pre> </td> </tr> </tbody> </table> <br /> <p> <b>实例二:用于h亲缘关系的进E间通信</b> </p> <p>下面例子l出了管道的具体应用Q父q程通过道发送一些命令给子进E,子进E解析命令,q根据命令作相应处理?/p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <unistd.h> #include <sys/types.h> main() { int pipe_fd[2]; pid_t pid; char r_buf[4]; char** w_buf[256]; int childexit=0; int i; int cmd; memset(r_buf,0,sizeof(r_buf)); if(pipe(pipe_fd)<0) { printf("pipe create error\n"); return -1; } if((pid=fork())==0) //子进E:解析从管道中获取的命令,q作相应的处? { printf("\n"); close(pipe_fd[1]); sleep(2); while(!childexit) { read(pipe_fd[0],r_buf,4); cmd=atoi(r_buf); if(cmd==0) { printf("child: receive command from parent over\n now child process exit\n"); childexit=1; } else if(handle_cmd(cmd)!=0) return; sleep(1); } close(pipe_fd[0]); exit(); } else if(pid>0) //parent: send commands to child { close(pipe_fd[0]); w_buf[0]="003"; w_buf[1]="005"; w_buf[2]="777"; w_buf[3]="000"; for(i=0;i<4;i++) write(pipe_fd[1],w_buf[i],4); close(pipe_fd[1]); } } //下面是子q程的命令处理函敎ͼ特定于应用)Q? int handle_cmd(int cmd) { if((cmd<0)||(cmd>256)) //suppose child only support 256 commands { printf("child: invalid command \n"); return -1; } printf("child: the cmd from parent is %d\n", cmd); return 0; } </pre> </td> </tr> </tbody> </table> <br /> <p> <a name="N100D7"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">1.5道的局限?/font> </strong> </span> </a> </p> <p>道的主要局限性正体现在它的特点上Q?/p> <ul> <li>只支持单向数据流Q? </li> <li>只能用于h亲缘关系的进E之_ </li> <li>没有名字Q? </li> <li>道的缓冲区是有限的Q管道制存在于内存中Q在道创徏Ӟ为缓冲区分配一个页面大)Q? </li> <li>道所传送的是无格式字节,q就要求道的读出方和写入方必须事先U定好数据的格式Q比如多字节算作一个消息(或命令、或记录Q等{; </li> </ul> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N100F2"> <span id="wmqeeuq" class="atitle">2?有名道概述及相关API应用</span> </a> </p> <p> <a name="N100F8"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2.1 有名道相关的关键概?/font> </strong> </span> </a> </p> <p>道应用的一个重大限制是它没有名字,因此Q只能用于具有亲~关pȝq程间通信Q在有名道Qnamed pipe或FIFOQ提出后Q该限制得到了克服。FIFO不同于管道之处在于它提供一个\径名与之兌Q以FIFO的文件Ş式存在于文gpȝ中。这P即与FIFO的创E不存在亲缘关系的进E,只要可以讉K该\径,p够彼此通过FIFO怺通信Q能够访问该路径的进E以及FIFO的创E之_Q因此,通过FIFO不相关的q程也能交换数据。值得注意的是QFIFO严格遵@先进先出Qfirst in first outQ,对管道及FIFO的读L从开始处q回数据Q对它们的写则把数据d到末。它们不支持诸如lseek(){文件定位操作?/p> <p> <a name="N10101"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2.2有名道的创?/font> </strong> </span> </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char * pathname, mode_t mode) </pre> </td> </tr> </tbody> </table> <br /> <p>该函数的W一个参数是一个普通的路径名,也就是创建后FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。如果mkfifo的第一个参数是一个已l存在的路径名时Q会q回EEXIST错误Q所以一般典型的调用代码首先会检查是否返回该错误Q如果确实返回该错误Q那么只要调用打开FIFO的函数就可以了。一般文件的I/O函数都可以用于FIFOQ如close、read、write{等?/p> <p> <a name="N1010E"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2.3有名道的打开规则</font> </strong> </span> </a> </p> <p>有名道比管道多了一个打开操作Qopen?/p> <p>FIFO的打开规则Q?/p> <p>如果当前打开操作是ؓ读而打开FIFOӞ若已l有相应q程为写而打开该FIFOQ则当前打开操作成功返回;否则Q可能阻塞直到有相应q程为写而打开该FIFOQ当前打开操作讄了阻塞标志)Q或者,成功q回Q当前打开操作没有讄d标志Q?/p> <p>如果当前打开操作是ؓ写而打开FIFOӞ如果已经有相应进Eؓ读而打开该FIFOQ则当前打开操作成功返回;否则Q可能阻塞直到有相应q程而打开该FIFOQ当前打开操作讄了阻塞标志)Q或者,q回ENXIO错误Q当前打开操作没有讄d标志Q?/p> <p>Ҏ开规则的验证参?<a ><font color="#996699">?</font></a>?</p> <p> <a name="N10127"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2.4有名道的读写规?/font> </strong> </span> </a> </p> <p>从FIFO中读取数据:</p> <p>U定Q如果一个进Eؓ了从FIFO中读取数据而阻塞打开FIFOQ那么称该进E内的读操作|了d标志的读操作?/p> <ul> <li>如果有进E写打开FIFOQ且当前FIFO内没有数据,则对于设|了d标志的读操作来说Q将一直阻塞。对于没有设|阻塞标志读操作来说则返?1Q当前errnogؓEAGAINQ提醒以后再试? </li> <li>对于讄了阻塞标志的L作说Q造成d的原因有两种Q当前FIFO内有数据Q但有其它进E在读这些数据;另外是FIFO内没有数据。解d的原因则是FIFO中有新的数据写入Q不Z写入数据量的大小Q也不论L作请求多数据量? </li> <li>L开的阻塞标志只Ҏq程W一个读操作施加作用Q如果本q程内有多个L作序列,则在W一个读操作被唤醒ƈ完成L作后Q其它将要执行的L作将不再dQ即使在执行L作时QFIFO中没有数据也一P此时Q读操作q回0Q? </li> <li>如果没有q程写打开FIFOQ则讄了阻塞标志的L作会d?</li> </ul> <p>注:如果FIFO中有数据Q则讄了阻塞标志的L作不会因为FIFO中的字节数小于请求读的字节数而阻塞,此时Q读操作会返回FIFO中现有的数据量?/p> <p>向FIFO中写入数据:</p> <p>U定Q如果一个进Eؓ了向FIFO中写入数据而阻塞打开FIFOQ那么称该进E内的写操作|了d标志的写操作?/p> <p>对于讄了阻塞标志的写操作:</p> <ul> <li>当要写入的数据量不大于PIPE_BUFӞlinux保证写入的原子性。如果此时管道空闲缓冲区不以容U写入的字节数Q则q入睡眠Q直到当~冲Z能够容纳要写入的字节数时Q才开始进行一ơ性写操作? </li> <li>当要写入的数据量大于PIPE_BUFӞlinux不再保证写入的原子性。FIFO~冲Z有空闲区域,写进E就会试囑֐道写入数据Q写操作在写完所有请求写的数据后q回?</li> </ul> <p>对于没有讄d标志的写操作Q?/p> <ul> <li>当要写入的数据量大于PIPE_BUFӞlinux不再保证写入的原子性。在写满所有FIFOI闲~冲区后Q写操作q回? </li> <li>当要写入的数据量不大于PIPE_BUFӞlinux保证写入的原子性。如果当前FIFOI闲~冲够容U求写入的字节敎ͼ写完后成功返回;如果当前FIFOI闲~冲Z能够容纳h写入的字节数Q则q回EAGAIN错误Q提醒以后再写; </li> </ul> <p>对FIFOd规则的验证:</p> <p>下面提供了两个对FIFO的读写程序,适当调节E序中的很少地方或者程序的命o行参数就可以对各UFIFOd规则q行验证?/p> <br /> <br /> <a name="N10169"> <b>E序1Q写FIFO的程?/b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define FIFO_SERVER "/tmp/fifoserver" main(int argc,char** argv) //参数为即写入的字节? { int fd; char w_buf[4096*2]; int real_wnum; memset(w_buf,0,4096*2); if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf("cannot create fifoserver\n"); if(fd==-1) if(errno==ENXIO) printf("open error; no reading process\n"); fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0); //讄非阻塞标? //fd=open(FIFO_SERVER,O_WRONLY,0); //讄d标志 real_wnum=write(fd,w_buf,2048); if(real_wnum==-1) { if(errno==EAGAIN) printf("write to fifo error; try later\n"); } else printf("real write num is %d\n",real_wnum); real_wnum=write(fd,w_buf,5000); //5000用于试写入字节大于4096时的非原子? //real_wnum=write(fd,w_buf,4096); //4096用于试写入字节不大?096时的原子? if(real_wnum==-1) if(errno==EAGAIN) printf("try later\n"); } </pre> </td> </tr> </tbody> </table> <br /> <br /> <br /> <a name="N10173"> <b>E序2Q与E序1一h试写FIFO的规则,W一个命令行参数是请求从FIFOd的字节数</b> </a> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define FIFO_SERVER "/tmp/fifoserver" main(int argc,char** argv) { char r_buf[4096*2]; int fd; int r_size; int ret_size; r_size=atoi(argv[1]); printf("requred real read bytes %d\n",r_size); memset(r_buf,0,sizeof(r_buf)); fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0); //fd=open(FIFO_SERVER,O_RDONLY,0); //在此处可以把ȝ序编译成两个不同版本Q阻塞版本及非阻塞版? if(fd==-1) { printf("open %s for read error\n"); exit(); } while(1) { memset(r_buf,0,sizeof(r_buf)); ret_size=read(fd,r_buf,r_size); if(ret_size==-1) if(errno==EAGAIN) printf("no data avlaible\n"); printf("real read bytes %d\n",ret_size); sleep(1); } pause(); unlink(FIFO_SERVER); } </pre> </td> </tr> </tbody> </table> <br /> <p>E序应用说明Q?/p> <p>把读E序~译成两个不同版本:</p> <ul> <li>dȝ?br </li> <li>以及非阻塞读版本nbr </li> </ul> <p>把写E序~译成两个四个版本:</p> <ul> <li>非阻塞且h写的字节数大于PIPE_BUF版本Qnbwg </li> <li>非阻塞且h写的字节C大于PIPE_BUF版本Q版本nbw </li> <li>d且请求写的字节数大于PIPE_BUF版本Qbwg </li> <li>d且请求写的字节数不大于PIPE_BUF版本Q版本bw </li> </ul> <p>下面用br、nbr、w代替相应E序中的d诅R非d?/p> <p>验证d写操作:</p> <ol> <li>当请求写入的数据量大于PIPE_BUF时的非原子性: <ul><li>nbr 1000 </li><li>bwg </li></ul></li> <li>当请求写入的数据量不大于PIPE_BUF时的原子性: <ul><li>nbr 1000 </li><li>bw </li></ul></li> </ol> <p>验证非阻塞写操作Q?/p> <ol> <li>当请求写入的数据量大于PIPE_BUF时的非原子性: <ul><li>nbr 1000 </li><li>nbwg </li></ul></li> <li>h写入的数据量不大于PIPE_BUF时的原子性: <ul><li>nbr 1000 </li><li>nbw </li></ul></li> </ol> <p>不管写打开的阻塞标志是否设|,在请求写入的字节数大?096Ӟ都不保证写入的原子性。但二者有本质区别Q?/p> <p>对于d写来_写操作在写满FIFO的空闲区域后Q会一直等待,直到写完所有数据ؓ止,h写入的数据最l都会写入FIFOQ?/p> <p>而非d写则在写满FIFO的空闲区域后Q就q回(实际写入的字节数)Q所以有些数据最l不能够写入?/p> <p>对于L作的验证则比较简单,不再讨论?/p> <p> <a name="N101E9"> <span id="wmqeeuq" class="smalltitle"> <strong> <font face="Arial">2.5有名道应用实例</font> </strong> </span> </a> </p> <p>在验证了相应的读写规则后Q应用实例似乎就没有必要了?/p> <br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <img height="1" alt="" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="100%" /> <br /> <img height="6" alt="" src="http://www.ibm.com/i/c.gif" width="8" border="0" /> </td> </tr> </tbody> </table> <table class="no-print" cellspacing="0" cellpadding="0" align="right"> <tbody> <tr align="right"> <td> <img height="4" alt="" src="http://www.ibm.com/i/c.gif" width="100%" /> <br /> <table cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td valign="center"> <img height="16" alt="" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /> <br /> </td> <td valign="top" align="right"> <a class="fbox" > <b> <font color="#996699">回页?/font> </b> </a> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <br /> <br /> <p> <a name="N101F2"> <span id="wmqeeuq" class="atitle">结Q?/span> </a> </p> <p>道常用于两个方面:Q?Q在shell中时怼用到道Q作入输入的重定向)Q在q种应用方式下,道的创建对于用h说是透明的;Q?Q用于具有亲~关pȝq程间通信Q用戯己创建管道,q完成读写操作?/p> <p>FIFO可以说是道的推q,克服了管道无名字的限Ӟ使得无亲~关pȝq程同样可以采用先进先出的通信机制q行通信?/p> <p>道和FIFO的数据是字节,应用E序之间必须事先定特定的传?协议"Q采用传播具有特定意义的消息?/p> <p>要灵zd用管道及FIFOQ理解它们的d规则是关键?/p> <p> <a name="a">?Qkill -l 的运行结果,昄了当前系l支持的所有信P </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 32) SIGRTMIN 33) SIGRTMIN+1 34) SIGRTMIN+2 35) SIGRTMIN+3 36) SIGRTMIN+4 37) SIGRTMIN+5 38) SIGRTMIN+6 39) SIGRTMIN+7 40) SIGRTMIN+8 41) SIGRTMIN+9 42) SIGRTMIN+10 43) SIGRTMIN+11 44) SIGRTMIN+12 45) SIGRTMIN+13 46) SIGRTMIN+14 47) SIGRTMIN+15 48) SIGRTMAX-15 49) SIGRTMAX-14 50) SIGRTMAX-13 51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9 55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5 59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1 63) SIGRTMAX </pre> </td> </tr> </tbody> </table> <br /> <p>除了在此处用来说明管道应用外Q接下来的专题还要对q些信号分类讨论?/p> <p> <a name="b">?Q对FIFO打开规则的验证(主要验证写打开对读打开的依赖性) </a> </p> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">#include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define FIFO_SERVER "/tmp/fifoserver" int handle_client(char*); main(int argc,char** argv) { int r_rd; int w_fd; pid_t pid; if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) printf("cannot create fifoserver\n"); handle_client(FIFO_SERVER); } int handle_client(char* arg) { int ret; ret=w_open(arg); switch(ret) { case 0: { printf("open %s error\n",arg); printf("no process has the fifo open for reading\n"); return -1; } case -1: { printf("something wrong with open the fifo except for ENXIO"); return -1; } case 1: { printf("open server ok\n"); return 1; } default: { printf("w_no_r return ----\n"); return 0; } } unlink(FIFO_SERVER); } int w_open(char*arg) //0 open error for no reading //-1 open error for other reasons //1 open ok { if(open(arg,O_WRONLY|O_NONBLOCK,0)==-1) { if(errno==ENXIO) { return 0; } else return -1; } return 1; } </pre> </td> </tr> </tbody> </table> <br /> <br /> <br /> <p> <a name="resources"> <span id="wmqeeuq" class="atitle">参考资?</span> </a> </p> <ul> <li>UNIX|络~程W二Pq程间通信Q作者:W.Richard StevensQ译者:杨张,清华大学出版C。丰富的UNIXq程间通信实例及分析,对Linux环境下的E序开发有极大的启发意义?br /><br /></li> <li>linux内核源代码情景分析(上、下Q,毛d操、胡希明著,江大学出版C,当要验证某个l论、想法时Q最好的参考资料;<br /><br /></li> <li>UNIX环境高~程Q作者:W.Richard StevensQ译者:晋元等Q机械工业出版社。具有丰富的~程实例Q以及关键函C随Unix的发展历E?br /><br /></li> <li> <a > <font color="#5c81a7">http://www.linux.org.tw/CLDP/gb/Secure-Programs-HOWTO/x346.html</font> </a>Ҏlinux下sigaction的实现基Qlinux源码../kernel/signal.c更说明了问题Q?<br /><br /></li> <li>pipe手册Q最直接而可靠的参考资?br /><br /></li> <li>fifo手册Q最直接而可靠的参考资?/li> </ul> <img src ="http://www.aygfsteel.com/lusm/aggbug/108291.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lusm/" target="_blank">qL~@@~</a> 2007-04-03 23:51 <a href="http://www.aygfsteel.com/lusm/archive/2007/04/03/108291.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]SHELL下十二种L件的Ҏhttp://www.aygfsteel.com/lusm/archive/2007/03/28/106999.htmlqL~@@~qL~@@~Wed, 28 Mar 2007 08:20:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/03/28/106999.htmlhttp://www.aygfsteel.com/lusm/comments/106999.htmlhttp://www.aygfsteel.com/lusm/archive/2007/03/28/106999.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/106999.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/106999.html阅读全文

qL~@@~ 2007-03-28 16:20 发表评论
]]>
[转]一个关于ftp破解的perlE序~~~~~~应网友要求,我找来一个不错的服务器入侵入门代码,也献l想学入늚朋友Q学术研IӞ本h不鼓励入侵)http://www.aygfsteel.com/lusm/archive/2007/02/21/100290.htmlqL~@@~qL~@@~Wed, 21 Feb 2007 03:53:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/02/21/100290.htmlhttp://www.aygfsteel.com/lusm/comments/100290.htmlhttp://www.aygfsteel.com/lusm/archive/2007/02/21/100290.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/100290.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/100290.html阅读全文

qL~@@~ 2007-02-21 11:53 发表评论
]]>
[转]Linux 汇编语言开发指?AT&T ~~~~~~~~~~~~ 入门好东?/title><link>http://www.aygfsteel.com/lusm/archive/2007/02/18/100180.html</link><dc:creator>qL~@@~</dc:creator><author>qL~@@~</author><pubDate>Sun, 18 Feb 2007 09:24:00 GMT</pubDate><guid>http://www.aygfsteel.com/lusm/archive/2007/02/18/100180.html</guid><wfw:comment>http://www.aygfsteel.com/lusm/comments/100180.html</wfw:comment><comments>http://www.aygfsteel.com/lusm/archive/2007/02/18/100180.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/lusm/comments/commentRss/100180.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/lusm/services/trackbacks/100180.html</trackback:ping><description><![CDATA[     摘要:   <a href='http://www.aygfsteel.com/lusm/archive/2007/02/18/100180.html'>阅读全文</a><img src ="http://www.aygfsteel.com/lusm/aggbug/100180.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/lusm/" target="_blank">qL~@@~</a> 2007-02-18 17:24 <a href="http://www.aygfsteel.com/lusm/archive/2007/02/18/100180.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]AT&T汇编http://www.aygfsteel.com/lusm/archive/2007/02/18/100179.htmlqL~@@~qL~@@~Sun, 18 Feb 2007 09:00:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/02/18/100179.htmlhttp://www.aygfsteel.com/lusm/comments/100179.htmlhttp://www.aygfsteel.com/lusm/archive/2007/02/18/100179.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/100179.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/100179.html阅读全文

qL~@@~ 2007-02-18 17:00 发表评论
]]>
[转]GCC参数解http://www.aygfsteel.com/lusm/archive/2007/02/14/99781.htmlqL~@@~qL~@@~Wed, 14 Feb 2007 02:19:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/02/14/99781.htmlhttp://www.aygfsteel.com/lusm/comments/99781.htmlhttp://www.aygfsteel.com/lusm/archive/2007/02/14/99781.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/99781.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/99781.html阅读全文

qL~@@~ 2007-02-14 10:19 发表评论
]]>
[转]S60 Python ~程指南——蓝牙连? 手机到PC)http://www.aygfsteel.com/lusm/archive/2007/02/13/99591.htmlqL~@@~qL~@@~Tue, 13 Feb 2007 01:20:00 GMThttp://www.aygfsteel.com/lusm/archive/2007/02/13/99591.htmlhttp://www.aygfsteel.com/lusm/comments/99591.htmlhttp://www.aygfsteel.com/lusm/archive/2007/02/13/99591.html#Feedback0http://www.aygfsteel.com/lusm/comments/commentRss/99591.htmlhttp://www.aygfsteel.com/lusm/services/trackbacks/99591.html阅读全文

qL~@@~ 2007-02-13 09:20 发表评论
]]>
վ֩ģ壺 ɯ| | ó| ״| | ˮ| ľ| | | | | | ˮ| | | | ƽ| ˫| ˮ| ĩ| | | | | | | | | | °Ͷ| »| ˮ| DZ| | | | | ½| ˲| ¦| |