posts - 200, comments - 8, trackbacks - 0, articles - 0

     摘要: 译自http://www.wangafu.net/~nickm/libevent-book/Ref5_evutil.html    转自:http://blog.sina.com.cn/s/blog_56dee71a0100qo9t.html<event2/util.h>定义了很多在实现可移植应用时有用的函数,libevent内部也使用这些类型和函数。1&...  阅读全文

posted @ 2013-02-05 14:19 鑫龙 阅读(6385) | 评论 (0)编辑 收藏

     摘要: 译自http://www.wangafu.net/~nickm/libevent-book/Ref4_event.html转自:http://blog.sina.com.cn/s/blog_56dee71a0100qi0y.htmllibevent的基本操作单元是事件。每个事件代表一组条件的集合,这些条件包括:v 文件描述符已经就绪,可以读取或者写入v 文件描述符变为就绪状态,...  阅读全文

posted @ 2013-02-04 17:59 鑫龙 阅读(5454) | 评论 (0)编辑 收藏

译自http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html
转自:http://blog.sina.com.cn/s/blog_56dee71a0100qe76.html

运行循环

一旦有了一个已经注册了某些事件的event_base(关于如何创建和注册事件请看下一节),就需要让libevent等待事件并且通知事件的发生。

接口
#define EVLOOP_ONCE             0x01
#define EVLOOP_NONBLOCK         0x02
#define EVLOOP_NO_EXIT_ON_EMPTY 0x04

int event_base_loop(struct event_base *baseint flags);

默认情况下,event_base_loop()函数运行event_base直到其中没有已经注册的事件为止。执行循环的时候,函数重复地检查是否有任何已经注册的事件被触发(比如说,读事件的文件描述符已经就绪,可以读取了;或者超时事件的超时时间即将到达)。如果有事件被触发,函数标记被触发的事件为“激活的”,并且执行这些事件。

在flags参数中设置一个或者多个标志就可以改变event_base_loop()的行为。如果设置了EVLOOP_ONCE,循环将等待某些事件成为激活的,执行激活的事件直到没有更多的事件可以执行,然会返回。如果设置了EVLOOP_NONBLOCK,循环不会等待事件被触发:循环将仅仅检测是否有事件已经就绪,可以立即触发,如果有,则执行事件的回调。

完成工作后,如果正常退出,event_base_loop()返回0;如果因为后端中的某些未处理错误而退出,则返回-1。

为帮助理解,这里给出event_base_loop()的算法概要:

伪代码

while (any events are registered with the loop,
        or EVLOOP_NO_EXIT_ON_EMPTY was 
set) {

    
if (EVLOOP_NONBLOCK was set, or any events are already active)
        If any registered events have triggered, mark them active.
    
else
        Wait until at least one 
event has triggered, and mark it active.

    
for (p = 0; p < n_priorities; ++p {
       
if (any event with priority of p is active) {
          Run all active events with priority of p.
          
break/* Do not run any events of a less important priority */
       }
    }

    
if (EVLOOP_ONCE was set or EVLOOP_NONBLOCK was set)
       
break;
}

为方便起见,也可以调用

接口

int event_base_dispatch(struct event_base *base);

event_base_dispatch()等同于没有设置标志的event_base_loop()。所以,event_base_dispatch()将一直运行,直到没有已经注册的事件了,或者调用了event_base_loopbreak()或者event_base_loopexit()为止。

这些函数定义在<event2/event.h>中,从libevent 1.0版就存在了。

停止循环

如果想在移除所有已注册的事件之前停止活动的事件循环,可以调用两个稍有不同的函数。

接口

int event_base_loopexit(struct event_base *base,
                        
const struct timeval *tv);
int event_base_loopbreak(struct event_base *base);

event_base_loopexit()让event_base在给定时间之后停止循环。如果tv参数为NULL,event_base会立即停止循环,没有延时。如果event_base当前正在执行任何激活事件的回调,则回调会继续运行,直到运行完所有激活事件的回调之才退出。

event_base_loopbreak()让event_base立即退出循环。它与event_base_loopexit(base,NULL)的不同在于,如果event_base当前正在执行激活事件的回调,它将在执行完当前正在处理的事件后立即退出。

注意event_base_loopexit(base,NULL)和event_base_loopbreak(base)在事件循环没有运行时的行为不同:前者安排下一次事件循环在下一轮回调完成后立即停止(就好像带EVLOOP_ONCE标志调用一样);后者却仅仅停止当前正在运行的循环,如果事件循环没有运行,则没有任何效果。

这两个函数都在成功时返回0,失败时返回-1。

示例:立即关闭

#include <event2/event.h>

/* Here's a callback function that calls loopbreak */
void cb(int sock, short what, void *arg)
{
    
struct event_base *base = arg;
    event_base_loopbreak(
base);
}

void main_loop(struct event_base *base, evutil_socket_t watchdog_fd)
{
    
struct event *watchdog_event;

    
/* Construct a new event to trigger whenever there are any bytes to
       read from a watchdog socket.  When that happens, we'll call the
       cb function, which will make the loop exit immediately without
       running any other active events at all.
     
*/
    watchdog_event 
= event_new(base, watchdog_fd, EV_READ, cb, base);

    event_add(watchdog_event, NULL);

    event_base_dispatch(
base);
}

示例:执行事件循环10秒,然后退出

#include <event2/event.h>

void run_base_with_ticks(struct event_base *base)
{
  
struct timeval ten_sec;

  ten_sec.tv_sec 
= 10;
  ten_sec.tv_usec 
= 0;

  
/* Now we run the event_base for a series of 10-second intervals, printing
     "Tick" after each.  For a much better way to implement a 10-second
     timer, see the section below about persistent timer events. 
*/
  
while (1) {
     
/* This schedules an exit ten seconds from now. */
     event_base_loopexit(
base&ten_sec);

     event_base_dispatch(
base);
     puts(
"Tick");
  }
}

有时候需要知道对event_base_dispatch()或者event_base_loop()的调用是正常退出的,还是因为调用event_base_loopexit()或者event_base_break()而退出的。可以调用下述函数来确定是否调用了loopexit或者break函数。

接口

int event_base_got_exit(struct event_base *base);
int event_base_got_break(struct event_base *base);

这两个函数分别会在循环是因为调用event_base_loopexit()或者event_base_break()而退出的时候返回true,否则返回false。下次启动事件循环的时候,这些值会被重设。

这些函数声明在<event2/event.h>中。event_break_loopexit()函数首次在libevent 1.0c版本中实现;event_break_loopbreak()首次在libevent 1.4.3版本中实现。

检查内部时间缓存

有时候需要在事件回调中获取当前时间的近似视图,但不想调用gettimeofday()(可能是因为OS将gettimeofday()作为系统调用实现,而你试图避免系统调用的开销)。

在回调中,可以请求libevent开始本轮回调时的当前时间视图。

接口

int event_base_gettimeofday_cached(struct event_base *base,
    
struct timeval *tv_out);

如果当前正在执行回调,event_base_gettimeofday_cached()函数设置tv_out参数的值为缓存的时间。否则,函数调用evutil_gettimeofday()获取真正的当前时间。成功时函数返回0,失败时返回负数。

注意,因为libevent在开始执行回调的时候缓存时间值,所以这个值至少是有一点不精确的。如果回调执行很长时间,这个值将非常不精确。

这个函数是libevent 2.0.4-alpha新引入的。

转储event_base的状态

接口

void event_base_dump_events(struct event_base *base, FILE *f);

为帮助调试程序(或者调试libevent),有时候可能需要加入到event_base的事件及其状态的完整列表。调用event_base_dump_events()可以将这个列表输出到指定的文件中。

这个列表是人可读的,未来版本的libevent将会改变其格式。

这个函数在libevent 2.0.1-alpha版本中引入。

废弃的事件循环函数

前面已经讨论过,老版本的libevent 具有“当前”event_base的概念。

本文讨论的某些事件循环函数具有操作当前event_base的变体。除了没有base参数外,这些函数跟当前新版本函数的行为相同。

注意

2.0版本之前的event_base是不支持锁的,所以这些函数并不是完全线程安全的:不允许在执行事件循环的线程之外的其他线程中调用_loopbreak()或者_loopexit()函数。

posted @ 2013-02-04 17:36 鑫龙 阅读(6102) | 评论 (0)编辑 收藏

     摘要: 译自http://www.wangafu.net/~nickm/libevent-book/Ref2_eventbase.html转自:http://blog.sina.com.cn/s/blog_56dee71a0100qdxx.html 使用libevent函数之前需要分配一个或者多个event_base结构体。每个event_base结构体持有一个事件集合,可以检测以确定哪个事件是...  阅读全文

posted @ 2013-02-04 17:18 鑫龙 阅读(3777) | 评论 (0)编辑 收藏

     摘要: 翻译自:http://www.wangafu.net/~nickm/libevent-book/Ref1_libsetup.html转自http://blog.sina.com.cn/s/blog_56dee71a0100q9ks.htmllibevent有一些被整个进程共享的、影响整个库的全局设置。必须在调用libevent库的任何其他部分之前修改这些设置,否则,libevent会进入不一致的状...  阅读全文

posted @ 2013-02-04 17:07 鑫龙 阅读(4618) | 评论 (0)编辑 收藏

翻译自:http://www.wangafu.net/~nickm/libevent-book/Ref0_meta.html
转自:
http://blog.sina.com.cn/s/blog_56dee71a0100q7j6.html

 从一万英尺外看Libevent

Libevent是用于编写高速可移植非阻塞IO应用的库,其设计目标是:

v 可移植性:使用libevent编写的程序应该可以在libevent支持的所有平台上工作。即使没有好的方式进行非阻塞IO,libevent也应该支持一般的方式,让程序可以在受限的环境中运行。

v 速度:libevent尝试使用每个平台上最高速的非阻塞IO实现,并且不引入太多的额外开销。

v 可扩展性:libevent被设计为程序即使需要上万个活动套接字的时候也可以良好工作。

v 方便:无论何时,最自然的使用libevent编写程序的方式应该是稳定的、可移植的。

 

libevent由下列组件构成:

v evutil:用于抽象不同平台网络实现差异的通用功能。

v event和event_base:libevent的核心,为各种平台特定的、基于事件的非阻塞IO后端提供抽象API,让程序可以知道套接字何时已经准备好,可以读或者写,并且处理基本的超时功能,检测OS信号。

v bufferevent:为libevent基于事件的核心提供使用更方便的封装。除了通知程序套接字已经准备好读写之外,还让程序可以请求缓冲的读写操作,可以知道何时IO已经真正发生。(bufferevent接口有多个后端,可以采用系统能够提供的更快的非阻塞IO方式,如Windows中的IOCP。)

v evbuffer:在bufferevent层之下实现了缓冲功能,并且提供了方便有效的访问函数。

v evhttp:一个简单的HTTP客户端/服务器实现。

v evdns:一个简单的DNS客户端/服务器实现。

v evrpc:一个简单的RPC实现。

 库

创建libevent时,默认安装下列库:

v libevent_core:所有核心的事件和缓冲功能,包含了所有的event_base、evbuffer、bufferevent和工具函数。

v libevent_extra:定义了程序可能需要,也可能不需要的协议特定功能,包括HTTP、DNS和RPC。

v libevent:这个库因为历史原因而存在,它包含libevent_core和libevent_extra的内容。不应该使用这个库,未来版本的libevent可能去掉这个库。

某些平台上可能安装下列库:

v libevent_pthreads:添加基于pthread可移植线程库的线程和锁定实现。它独立于libevent_core,这样程序使用libevent时就不需要链接到pthread,除非是以多线程方式使用libevent。

v libevent_openssl:这个库为使用bufferevent和OpenSSL进行加密的通信提供支持。它独立于libevent_core,这样程序使用libevent时就不需要链接到OpenSSL,除非是进行加密通信。

3 头文件

libevent公用头文件都安装在event2目录中,分为三类:

v API头文件:定义libevent公用接口。这类头文件没有特定后缀。

v 兼容头文件:为已废弃的函数提供兼容的头部包含定义。不应该使用这类头文件,除非是在移植使用较老版本libevent的程序时。

v 结构头文件:这类头文件以相对不稳定的布局定义各种结构体。这些结构体中的一些是为了提供快速访问而暴露;一些是因为历史原因而暴露。直接依赖这类头文件中的任何结构体都会破坏程序对其他版本libevent的二进制兼容性,有时候是以非常难以调试的方式出现。这类头文件具有后缀“_struct.h”。

(还存在不在event2目录中的较老版本libevent的头文件,请参考下节:如果需要使用老版本libevent)

4 如果需要使用老版本libevent

libevent 2.0以更合理的、不易出错的方式修正了API。如果可能,编写新程序时应该使用libevent 2.0。但是有时候可能需要使用较老的API,例如在升级已存的应用时,或者支持因为某些原因不能安装2.0或者更新版本libevent的环境时。

较老版本的libevent头文件较少,也不安装在event2目录中。

在2.0以及以后版本的libevent中,老的头文件仍然会作为新头文件的封装而存在。

其他关于使用较老版本的提示:

v 1.4版之前只有一个库libevent,它包含现在分散到libevent_core和libevent_extra中的所有功能。

v 2.0版之前不支持锁定:只有确定不同时在多个线程中使用同一个结构体时,libevent才是线程安全的。

下面的节还将讨论特定代码区域可能遇到的已经废弃的API。

5 关于版本状态的提示

1.4.7及以前版本应该被认为是完全废弃的。1.3之前的版本应该被认为是充满bug的。

(此外,不要向libevent维护者发送任何关于1.4.x或者更早版本的新特征,这些版本被认为是稳定的发布版本。如果在1.3x或者更早版本中发现bug,在报告之前请确定在最新的稳定发布版本中问题仍然存在:后续发布可能已经解决了问题。)


 

posted @ 2013-02-04 16:58 鑫龙 阅读(2931) | 评论 (0)编辑 收藏

     摘要: 原文出处:http://www.wangafu.net/~nickm/libevent-book/01_intro.html转自: http://blog.sina.com.cn/s/blog_56dee71a0100q2i9.html大多数程序员从阻塞IO调用开始学习。如果调用在操作完成之前,或者足够的时间已经流逝使得网络栈放弃操作之前,不会返回,那么就是异步的。比如说,在TCP连接上...  阅读全文

posted @ 2013-02-04 16:24 鑫龙 阅读(3071) | 评论 (0)编辑 收藏

前言

    可以说对于任何网络库(模块)而言,一个缓冲模块都是必不可少的。缓冲模块主要用于缓冲从网络接收到的数据,以及
用户提交的数据(用于发送)。很多时候,我们还需要将网络模块层(非TCP层)的这些缓冲数据拷贝到用户层,而这些内存拷贝
都会消耗时间。
    在这里,我简要分析下libevent的相关代码(event.h和buffer.c)。

结构

    关于libevent的缓冲模块,主要就是围绕evbuffer结构体展开。先看下evbuffer的定义:

struct evbuffer{
  
// 当前有效缓冲区的内存起始地址
 u_char *buffer; 
  
// 整个分配(realloc)用来缓冲的内存起始地址
  u_char *orig_buffer; 
  
// origin_buffer和buffer之间的字节数
 size_t misalign; 
  
// 整个分配用来缓冲的内存字节数
 size_t totallen; 
  
// 当前有效缓冲区的长度(字节数)
 size_t off; 
  
//回到函数,当缓冲区有变化的时候会被调用
 void (*cb)(struct evbuffer *, size_t, size_t, void *);
  
//回调函数的参数
 void *cbarg; 
};
 libevent的缓冲是一个连续的内存区域,其处理数据的方式(写数据和读数据)更像一个队列操作方式:从后写入,从前
读出。evbuffer分别设置相关指针(一个指标)用于指示读出位置和写入位置。其大致结构如图:

    orig_buffer指向由realloc分配的连续内存区域,buffer指向有效数据的内存区域,totallen表示orig_buffer指向的内存
区域的大小,misalign表示buffer相对于orig_buffer的偏移,off表示有效数据的长度。

实际运作

    这里我将结合具体的代码分析libevent是如何操作上面那个队列式的evbuffer的,先看一些辅助函数:

void evbuffer_drain(struct evbuffer *buf, size_t len)

 

    该函数主要操作一些指标,当每次从evbuffer里读取数据时,libevent便会将buffer指针后移,同时增大misalign,减小off,
而该函数正是做这件事的。说白了,该函数就是用于调整缓冲队列的前向指标。


int evbuffer_expand(struct evbuffer *buf, size_t datlen)

 

    该函数用于扩充evbuffer的容量。每次向evbuffer写数据时,都是将数据写到buffer+off后,buffer到buffer+off之间已被
使用,保存的是有效数据,而orig_buffer和buffer之间则是因为读取数据移动指标而形成的无效区域。
    evbuffer_expand的扩充策略在于,首先判断如果让出orig_buffer和buffer之间的空闲区域是否可以容纳添加的数据,如果
可以,则移动buffer和buffer+off之间的数据到orig_buffer和orig_buffer+off之间(有可能发生内存重叠,所以这里移动调用的
是memmove),然后把新的数据拷贝到orig_buffer+off之后;如果不可以容纳,那么重新分配更大的空间(realloc),同样会移动
数据。
    扩充内存的策略为:确保新的内存区域最小尺寸为256,且以乘以2的方式逐步扩大(256、512、1024、...)。

    了解了以上两个函数,看其他函数就比较简单了。可以看看具体的读数据和写数据:


int evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)

 

    该函数用于添加一段用户数据到evbuffer中。很简单,就是先判断是否有足够的空闲内存,如果没有则调用evbuffer_expand
扩充之,然后直接memcpy,更新off指标。


int evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)

 

    该函数用于将evbuffer中的数据复制给用户空间(读数据)。简单地将数据memcpy,然后调用evbuffer_drain移动相关指标。


struct evbuffer* evbuffer_new(void)
动态分配一个struct evbuffer结构,需要调用evbuffer_free释放内存。

void evbuffer_free(struct evbuffer *buffer)
释放buffer所占用的内存。

int evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)

移动数据从一个evbuffer到另一个evbuffer。

实际上还是调用了evbuffer_add添加数据到outbuf中。但会清除inbuf中的数据。

返回值:成功返回0, 失败返回-1。


int evbuffer_add_printf( struct evbuffer *const char* fmt, )
添加一个格式化的字符串到evbuffer尾部。


u_char *evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)

查找缓冲区中是否存在指定的字符串what。

注意这里使用的是u_char类型,说明有可能查找的数据不是以’\0’结尾

如果存在返回指向字符串what的指针,没有则返回NULL。


int evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
调用read/recv函数,从文件描述符fd上读取数据到evbuffer中。如果缓冲区不够,调用evbuffer_expand扩充缓冲区。

int evbuffer_write(struct evbuffer *buffer, int fd)
把缓冲区中的数据,调用send/write函数写入文件描述符fd上, 如果send/write函数写入的字节数大于0,则调用evbuffer_drain删除已写的数据。

char *evbuffer_readline(struct evbuffer *buffer)

读取数据以"\r\n","\n\r", "\r" 或者 "\n"结尾。

返回动态分配内存,需要调用者自己使用free来释放内存。返回一个以\0结尾的字符串。


void evbuffer_setcb(struct evbuffer *buffer,
    
void (*cb)(struct evbuffer *, size_t, size_t, void *),
    
void *cbarg)
设置回调函数。当缓冲区中发生变化时, 调用设置的回调函数。

Evbuffer提供的API已经全部介绍完毕,接下来我们通过一个实例进一步学习如何使用evbuffer, 想要使用evbuffer,系统里必须已经安装了libevent。

例子代码如下:evbuffer-test.c

#include <stdio.h>
#include <string.h>
#include <assert.h>

//引入libevent头文件
#include "event.h"

int main(int argc, char** argv)
{
    
struct evbuffer* buff = NULL;
    
char c, c2[3= {0};
    

    
buff = evbuffer_new();
    
assert(buff != NULL);
    

    
evbuffer_add(buff, "1"1);
    
evbuffer_add(buff, "2"1);
    
evbuffer_add(buff, "3"1);
    
evbuffer_add_printf(buff, "%d%d"45);
    
assert(buff->off == 5);

    
evbuffer_remove(buff, &c, sizeof(char));
    
assert(c == '1');
    
evbuffer_remove(buff, &c, sizeof(char));
    
assert(c == '2');
    
evbuffer_remove(buff, &c, sizeof(char));
    
assert(c == '3');
    
evbuffer_remove(buff, c2, 2);
    
assert(strcmp(c2, "45"== 0);
    

    
assert(buff->off == 0);
  

    
evbuffer_add(buff, "test\r\n"6);
    
assert(buff->off == 6);
    

    
char* line = evbuffer_readline(buff);
    
assert(strcmp(line, "test"==0);
    
assert(buff->off == 0);
    
free(line);
   

    
evbuffer_free(buff);
    

    
printf("ok\n");
    

    
return 0;
}

 

 

posted @ 2013-02-01 20:15 鑫龙 阅读(13909) | 评论 (0)编辑 收藏

     摘要: 回顾:  线程与进程  1.进程由于资源独立,进程的主要关注是解决资源共享  2.线程先天是数据共享,线程主要关注共享数据脏    1.互斥量(线程内)       读写锁    2.信号/条件量调度...  阅读全文

posted @ 2013-01-29 18:35 鑫龙 阅读(500) | 评论 (0)编辑 收藏

       在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别,可以说是完全不同。在进程环境中,对信号的处理是,先注册信号处理函数,当信号异步发生时,调用处理函数来处理信号。它完全是异步的(我们完全不知到信号会在进程的那个执行点到来!)。然而信号处理函数的实现,有着许多的限制;比如有一些函数不能在信号处理函数中调用;再比如一些函数read、recv等调用时会被异步的信号给中断(interrupt),因此我们必须对在这些函数在调用时因为信号而中断的情况进行处理(判断函数返回时 enno 是否等于 EINTR)。


       但是在多线程中处理信号的原则却完全不同,它的基本原则是:将对信号的异步处理,转换成同步处理,也就是说用一个线程专门的来“同步等待”信号的到来,而其它的线程可以完全不被该信号中断/打断(interrupt)。这样就在相当程度上简化了在多线程环境中对信号的处理。而且可以保证其它的线程不受信号的影响。这样我们对信号就可以完全预测,因为它不再是异步的,而是同步的我们完全知道信号会在哪个线程中的哪个执行点到来而被处理!。而同步的编程模式总是比异步的编程模式简单。其实多线程相比于多进程的其中一个优点就是:多线程可以将进程中异步的东西转换成同步的来处理。

1. sigwait函数:
sigwait等一个或者多个指定信号发生。
    它所做的工作只有两个:第一,监听被阻塞的信号;第二,如果所监听的信号产生了,则将其从未决队列中移出来(这里实时信号和非实时信号又有区别,体现在取出的顺序等,具体自己取网上查,这里不再详述)。sigwait并不改变信号掩码的阻塞与非阻塞状态。
    在POSIX标准中,当进程收到信号时,如果是多线程的情况,我们是无法确定是哪一个线程处理这个信号。而sigwait是从进程中pending的信号中,取走指定的信号。这样的话,如果要确保sigwait这个线程收到该信号,那么所有线程含主线程以及这个sigwait线程则必须block住这个信号,因为如果自己不阻塞就没有未决状态(阻塞状态)信号,别的所有线程不阻塞就有可能当信号过来时,被其他的线程处理掉。
记住:
     在多线程代码中,总是使用sigwait或者sigwaitinfo或者sigtimedwait等函数来处理信号。
     而不是signal或者sigaction等函数。因为在一个线程中调用signal或者sigaction等函数会改变所以线程中的
     信号处理函数。而不是仅仅改变调用signal/sigaction的那个线程的信号处理函数。

2. pthread_sigmask函数:
   每个线程均有自己的信号屏蔽集(信号掩码),可以使用pthread_sigmask函数来屏蔽某个线程对某些信号的
   响应处理,仅留下需要处理该信号的线程来处理指定的信号。实现方式是:利用线程信号屏蔽集的继承关系
  (在主进程中对sigmask进行设置后,主进程创建出来的线程将继承主进程的掩码

3. pthread_kill函数:
   在多线程程序中,一个线程可以使用pthread_kill对同一个进程中指定的线程(包括自己)发送信号。注意在多线程中  
  一般不使用kill函数发送信号,因为kill是对进程发送信号,结果是:正在运行的线程会处理该信号,如果该线程没有
 注册信号处理函数,那么会导致整个进程退出。
记住:调用sigwait同步等待的信号必须在调用线程中被屏蔽,并且通常应该在所有的线程中被屏蔽(这样可以保证信号绝不会被送到除了调用sigwait的任何其它线程),这是通过利用信号掩码的继承关系来达到的。

posted @ 2013-01-18 16:52 鑫龙 阅读(683) | 评论 (0)编辑 收藏

仅列出标题
共20页: First 3 4 5 6 7 8 9 10 11 Last