日期:2014-05-16  浏览次数:20692 次

线程不可中断睡眠与异步IO
各位大神,你们好
最近写了一个简单的程序,pthread多线程并发,每个线程会读取一个文件中的一个文件地址的数据,大约有300个线程同时读取的时候,有几个线程进入了不可中断睡眠状态,最后只剩下几个大约5~6个,此时cpu利用率0,内存空间利用率不变,请问这是怎么回事儿啊?就剩下那么几个,这个读写的磁盘还不能够为他们服务吗?
1.我想问的问题就是为什么他们会进入不可中断睡眠?
2.有人说用异步I/O,异步IO可以通过设定信号和处理函数,或者线程回调函数来避免不可中断睡眠?请问这又是为什么?
   一般的read函数读取时争夺资源,异步读取也是争夺资源,为什么同步read会进入不可中断睡眠,异步的不会呢?

谢谢!
------解决方案--------------------
1.我想问的问题就是为什么他们会进入不可中断睡眠?
这与你打开的文件有关联,你打开的设备或文件系统实现时为了避免资源竞争内部添加了信号量,一般的实现,默认在open时为O_ONBLOCK类型,它们不会进入睡眠状态,除非你指定为了O_BLOCK,你在调用read系统调用的时候会进入睡眠状态,在你上面的代码当中因为线程函数未使用循环,所以在默认情况下,299个线程会依次全部退出(read返回-EAGAIN),只有一个线程会真正的读取。你所说的线程进入了不可中断睡眠除非你指定了O_BLOCK。

2.有人说用异步I/O,异步IO可以通过设定信号和处理函数,或者线程回调函数来避免不可中断睡眠?请问这又是为什么?
异步IO也有很多方式来实现,poll、select、信号驱动IO、aio系列。
这些异步IO的实现本质上是在内核里面创建了线程来等待数据的到来,然后再发送到用户空间,调用这些函数会立即返回,它们不会因为没有数据而进入睡眠状态,当有数据到来时,内核可以通过信号通知要求获取数据的进程,或者使用aio实时扩展。

一般的read函数读取时争夺资源,异步读取也是争夺资源,为什么同步read会进入不可中断睡眠,异步的不会呢?
read当读不到数据的时候可能会阻塞,考虑你从网络上读取数据,调用recvfrom系统调用,该函数不会立即返回,而是等待有人向UDP端口发送数据后再返回。
而异步确保了系统调用会立刻返回,让你干其它的事情,等数据到来了会通知你。
下面是一个信号驱动IO的例子

/*
 * asynctest.c: use async notification to read stdin
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
 
int gotdata=0;
void sighandler(int signo)
{
    if (signo==SIGIO)
        gotdata++;
    return;
}
 
char buffer[4096];
 
int main(int argc, char **argv)
{
    int count;
    struct sigaction action;
 
    memset(&action, 0, sizeof(action));
    action.sa_handler = sighandler;
    action.sa_flags = 0;
 
    sigaction(SIGIO, &action, NULL);
 
    fcntl(STDIN_FILENO, F_SETOWN, getpid());
    fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) 
------解决方案--------------------
 FASYNC);
 
    while(1) {
        /* this only returns if a&nb