1. 程式人生 > >非同步IO(來自部落格園)

非同步IO(來自部落格園)

結合阻塞與非阻塞訪問、poll 函式可以較好地解決裝置的讀寫,但是如果有了非同步通知就更方便了。非同步通知的意思是:一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上“中斷”地概念,比較準確的稱謂是:訊號驅動(SIGIO)的非同步 I/O。可以使用signal()函式來設定對應的訊號的處理函式。函式原型是:

void (*signal(int signo,void (*func)(int))) (int)

我們先來看一個使用訊號驅動的例子,通過signal(SIGIO,input_handler) 對開啟的檔案fd 啟動訊號機制,輸入可獲得時inputhandler被呼叫,程式碼如下:

/*async_io_app.c*/

複製程式碼
#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <fcntl.h>

#include <signal.h>

#include <unistd.h>

#include <stdlib.h>

#define MAX_LEN 100

int fd;

void input_handler(int num)
{

    char data[MAX_LEN];

    int
len; //讀取並輸出 STDIN_FILENO 上的輸入 len = read(fd, &data, MAX_LEN); data[len] = 0; printf("input available:%s\n", data); } int main() { int oflags; //啟動訊號驅動機制 fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR); if(fd == -1)
{ printf(
"Device Open Failure !\n
"); exit(0); } signal(SIGIO, input_handler); fcntl(fd, F_SETOWN, getpid()); oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags | FASYNC); //最後進入一個死迴圈,程式什麼都不幹了,只有訊號能激發 input_handler 的執行 //如果程式中沒有這個死迴圈,會立即執行完畢 while (1); return 0; }
複製程式碼

下面來解釋一下上面的程式碼。為了一個使用者在使用者空間中能處理一個裝置釋放的訊號,它必須完成一下3份工作:

 1)通過F_SETOWN控制指令設定裝置檔案的擁有者為本程序,這樣從裝置驅動中發出的訊號才能被本程序收到。

 2)通過F_SETFL 控制命令設定裝置檔案支援FASYNC,即非同步通知模式。

 3)通過signal()連結訊號和訊號處理函式。

有了訊號的傳送,那麼就一定得有訊號的釋放了:

  在裝置驅動和應用程式的非同步通知互動中,僅僅在應用程式端捕獲訊號是不夠的,因為訊號沒有的源頭是在驅動端,因此要在適當的時機讓裝置驅動釋放訊號。

 為了使裝置支援非同步通知機制,驅動程式中涉及三個操作:

 1)支援F_SETOWN命令,能在這個控制命令處理中設定filp->f_owner為對應的程序ID。不過此項工作已由核心完成,裝置驅動無須處理。

 2)支援F_SETFL命令的處理,每當FASYNC標誌改變時,驅動程式中fasync()函式將得以進行。因此,驅動程式必須實現fasync()函式。

 3)在裝置資源可獲得時,呼叫kill_fasync()函式激發相應的訊號。

 驅動程式中上面的三步是和應用程式是一一對應的。如下圖:

裝置驅動中非同步通知程式設計還是比較簡單的,主要就是一些資料結構,和兩個函式:

資料結構:fasync_struct結構體

函式:1)處理FASYNC標誌變更的函式int fasync_helper(int fd, struct file *filp, int mode ,struct fasync_struct **fa);

2) 釋放訊號用的函式void kill_fasync(struct fasync_struct **fa, int sig, int band);

和其他裝置驅動一樣,一般將fasync_struct放到裝置結構體中。

下面給出驅動程式部分實現支援非同步IO的程式碼:

/* async_io_driver.c */

#include <linux/module.h>

#include <linux/init.h>

#include <linux/fs.h>

#include <asm/uaccess.h>

#include <linux/wait.h>

#include <linux/semaphore.h>

#include <linux/device.h>

#include <linux/cdev.h>

#include <linux/sched.h>

#include <linux/fcntl.h>

#include <linux/poll.h>

MODULE_LICENSE("GPL");

#define LEN  30

#define init_MUTEX(LOCKNAME) sema_init(LOCKNAME,1)

#define DEVICE_NAME  "CDEV_ZHU"

static struct class *cdev_class;

struct asycIO                                    

{                                                        

  struct cdev dev_c; /*cdev結構體*/   

  dev_t  dev; 

  char  mem[LEN];

  int   flag ;

  struct semaphore sem; /*併發控制用的訊號量*/          

  wait_queue_head_t r_wait; /*阻塞讀用的等待佇列頭*/    

  struct fasync_struct *async_queue; /* 非同步結構體指標,用於讀 */

};

struct asycIO  asyc_device;

static int asyc_io_fasync(int fd, struct file *filp, int mode)

{

         return fasync_helper(fd, filp, mode, &asyc_device.async_queue);

}

/*檔案釋放函式*/

int asyc_io_release(struct inode *inode, struct file *filp)

{

         /* 將檔案從非同步通知列表中刪除 */

  asyc_io_fasync( - 1, filp, 0);

  return 0;

}

/*寫操作*/

static ssize_t asyc_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)

{

   int ret = count;

  printk("In asyc_write! \n");

  down(&asyc_device.sem);  //獲取訊號量

  memset(asyc_device.mem,0,LEN);

  if (copy_from_user(asyc_device.mem, buf, count))

  {

        up(&asyc_device.sem);

        return    - EFAULT;

  }

  printk("kernel recieve: %s  and the length is %d \n",asyc_device.mem,count);

  up(&asyc_device.sem);

  asyc_device.flag = 1;

  if (asyc_device.async_queue)

       kill_fasync(&asyc_device.async_queue, SIGIO, POLL_IN);

  wake_up_interruptible(&asyc_device.r_wait);

  return ret;

}

static ssize_t asyc_read(struct file *filp, char *buf, size_t len, loff_t *off)

{

         int ret = len;

         printk("In asyc_read \n");

    if (wait_event_interruptible(asyc_device.r_wait, asyc_device.flag != 0))

    {

        return    - ERESTARTSYS;

    }

    if (down_interruptible(&asyc_device.sem))

    {

        return    - ERESTARTSYS;

    }

    asyc_device.flag = 0;

    if (copy_to_user(buf, asyc_device.mem, len))

    {

        up(&asyc_device.sem);

        return    - EFAULT;

    }

    up(&asyc_device.sem);

    return ret;

}

struct file_operations asyc_fops =

{

         read: asyc_read,

         write: asyc_write,

         fasync: asyc_io_fasync,

         release: asyc_io_release,

};

static int __init asyc_init(void)

{

    int ret,err;

    ret = alloc_chrdev_region(&(asyc_device.dev),0,1,DEVICE_NAME) ;

    if (ret)

    {

        printk("globalvar register failure");

    }

    else

    {

                   cdev_init(&(asyc_device.dev_c),&asyc_fops);

                   err = cdev_add(&(asyc_device.dev_c),asyc_device.dev,1);

                   if(err)

                   {

                            printk(KERN_NOTICE "error %d adding FC_dev\n",err);

                            unregister_chrdev_region(asyc_device.dev, 1);

                            return err;

                   }

                   else

                   {

                            printk("device register success! \n");

                   }

                   cdev_class = class_create(THIS_MODULE,DEVICE_NAME);

                   if(IS_ERR(cdev_class))

                   {

                            printk("ERR:cannot create a cdev_class\n"); 

                            unregister_chrdev_region(asyc_device.dev, 1);

                            return -1;

                   }

                   device_create(cdev_class, NULL, asyc_device.dev, 0, DEVICE_NAME);

                   asyc_device.flag = 0;

                   init_MUTEX(&(asyc_device.sem));

                   init_waitqueue_head(&(asyc_device.r_wait));

    }

    return ret;

static void __exit asyc_exit(void)

{

         device_destroy(cdev_class,asyc_device.dev);

         class_destroy(cdev_class);

         unregister_chrdev_region(asyc_device.dev,1);

         printk(" device exit! \n");

}

module_init(asyc_init);

module_exit(asyc_exit);

應用程式實現寫入功能:

/* async_io_app_w.c*/

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <fcntl.h>

#include <string.h>

int main()

{

    int fd, num;

    char buffer[100] = {0};

    fd = open("/dev/CDEV_ZHU", O_RDWR, S_IRUSR | S_IWUSR);

    printf("open /dev/CDEV_ZHU fd = %d \n",fd);

    if (fd != -1)

    {

        while (1)

        {

             memset(buffer,0,sizeof(buffer));

            printf("Please input the buffer:\n");

            scanf("%s", buffer);

             if (buffer[0] == '0') //如果輸入 0,退出

            {

                close(fd);

                break;

            }

            write(fd, buffer, strlen(buffer));   

            printf("We have written: %s\n",buffer);

        }

    }

    else

    {

        printf("device open failure\n");

    }

         return 0;

}

將上面的“async_io_app.c”、“async_io_driver.c”、“async_io_app_w.c”進行編譯,載入驅動之後,開兩個終端,分別執行async_io_app 和 async_io_app_w,當async_io_app_w有資料寫入的時候,async_io_app的終端會列印所寫入的資料,當然核心也會列印資料,下面是結果:

 說明:上面圖是三個終端的列印結果,從左到右一次是async_io_app_w , async_io_app 和使用dmesg 列印核心的結果。

注:我本來也想用程式碼格式,但是感覺在vim上排版很舒服的,上來用程式碼格式反而還不好看了,於是就這樣了 

相關推薦

非同步IO來自部落

結合阻塞與非阻塞訪問、poll 函式可以較好地解決裝置的讀寫,但是如果有了非同步通知就更方便了。非同步通知的意思是:一旦裝置就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢裝置狀態,這一點非常類似於硬體上“中斷”地概念,比較準確的稱謂是:訊號驅動(SIGIO)的非同

BBS+ BLOG系統仿部落

一、基本要求 作業題目:開發BBS+BLOG系統 作業需求: 1 基於ajax和使用者認證元件實現登入驗證 2 基於ajax和form元件實現註冊功能 3 系統首頁文章列表的渲染 4 個人站點頁面設計5 文章詳細頁的繼承6 點贊與踩滅7 評論功能8 富文字編輯器的使用9 防止xss攻擊

jquery學習入門到高階轉載部落

什麼是jQuery jQuery是一套Javascript指令碼庫.  在我的部落格中可以找到"Javascript輕量級指令碼庫"系列文章. Javascript指令碼庫類似於.NET的類庫, 我們將一些工具方法或物件方法封裝在類庫中, 方便使用

Spring 在多執行緒中,bean的注入問題部落

最近碰到了一個問題,使用SSM框架,在Service層需要另開一個執行緒,這個執行緒專門用來做一些操作,並將結果寫入資料庫中。但是線上程中使用@Resource或者@Autowired注入全部為NULL,原來是Spring不能線上程中注入。網上的主要解決方法有:將需要的Bean作為執行緒的的建構函式的引數傳入

從CSDN部落搬家到wordpress

最近自己搞了個域名,想把自己在CSDN上面的部落格全部轉到wordpress上面(雖然說自己在CSDN上寫部落格的時間並不是很長,呵呵)。 第一步 CSDN是沒有匯出功能的,所以我先在部落格園註冊了一個賬號,然後把自己在CSDN上面的部落格全部轉到了部落格園上面。

線路人生EP2C5/8啟蒙板檢測部落遷移

  閒魚是個好東西,兩套CycloneⅡ的開發板只要40,關鍵還是包郵。雖然說產品升級了N代了,不過這個價格就算拆件也值了。板子框圖、實拍圖如下:

線路人生EP2C5/8啟蒙板檢測-續 部落遷移

果然驗證了我的猜測,加上自制的244緩衝驅動隔離小板後,山寨下載器又恢復了神勇,立馬檢測到FPGA晶片了。

Lesson02:八位LED發光管操作部落遷移

LED發光二極體是最常用的輸出指示裝置,具有操作簡單、價格低廉的優點。相應的電路原理圖如圖2.1所示:

Lesson01:W-A_51微控制器實訓板介紹部落遷移

一、開發板介紹 微控制器實訓板是以Atmel公司的AT89S52微控制器為核心的實驗板,主要資源包括以下部分: 1、輸入單元——四個獨立按鍵/十六個矩陣按鍵(通過短路帽跳線選擇),一個PS2鍵盤/滑鼠介面 2、輸出單元——八位LED發光管/四位動態掃描數碼管/1602液晶(

TFT液晶研究部落遷移

TFT液晶研究  淘寶上買了幾款TFT裸片,帶8080介面,價效比很高。原先專案上用到的4.3寸TFT要100多,而且手上還有一些STM32的開發板,就想給這些板子配上液晶模組。 一、TFT液晶屏引數

python部落開發window7上Error loading MySQLdb module: No module named MySQLdb解決辦法

在windows環境中(win7),建立虛擬環境,django建好模型準備遷移資料,執行命令:,出現如下錯誤: (virtualenv) D:\workspace\blog_project>python manage.py makemigrations Traceba

完成埠(Completion Port)詳解 轉載來自部落----- By PiggyXP(小豬)

   完成埠(Completion Port)詳解                                                              ----- By PiggyXP(小豬) 前 言      

部落搬家系列-爬取部落部落

部落格搬家系列(三)-爬取部落格園部落格 一.前情回顧  部落格搬家系列(一)-簡介:https://blog.csdn.net/rico_zhou/article/details/83619152  部落格搬家系列(二)-爬取CSDN部落格:https://bl

如何更改自己部落部落的背景

首先 , 先開啟部落格園的首頁 -> 我的部落格-> 管理-> 設定 ->  找到頁面定製CSS程式碼然後貼上下文程式碼 /* 程式碼高亮開始,使用了一個叫Monokai Sublime的黑色主題面板,直接拿過來還不行,有一些樣式衝突,還要自己稍微改一些地方 Mon

python3爬蟲例子02獲取個人部落的文章資訊

#!/usr/bin/env python# -*- coding:UTF-8 -*-import requestsfrom bs4 import BeautifulSoupres=requests.get("https://www.cnblogs.com/NiceTime/")# c=res.content

比較全面的Eclipse配置詳解包括智慧提示設定、智慧提示外掛修改,修改空格自動上屏、JDK配置、各種快捷鍵列表…… - decarl - 部落

Eclipse編輯器基本設定 1、新增行號 在邊緣處右鍵 2、改字型 字型的一般配置 3、去掉拼寫錯誤檢查 4、Java程式碼風格 程式碼格式化 Ctrl + Shift + F 之後點選右邊的New按鈕,新建一個風格。

Oracle database和client 安裝教程轉自部落,用於備忘

** database ** 1.先到Oracle官網上下載11g oracle Database 11g 第 2 版 (11.2.0.1.0) 標準版、標準版 1 以及企業版 適用於 Microsoft Windows (x64) 的 Oracle Datab

從csdn搬家到部落無盡的藍黃

用csdn寫部落格已經有兩年多了,可以說csdn記錄了我作為IOer兩年來的經歷。 但是用久了也覺得csdn似乎有些差強人意, 1、介面太單調了,也不能改改背景之類的,為了給讀者更好的觀博體驗,我覺

關於多執行緒的幾點總結部落遷移

 關於執行緒 synchronized關鍵字:  不能用在變數和建構函式上  放在方法上面,鎖定的是物件,放在靜態方法上鎖定的是類  不應該鎖定常量,比如String等型別因為程式中這個物件難免還會用

學習部落開原始碼筆記

index.android.js或者index.ios.js是專案的開始介面, 很簡單的一個介面,註冊了一個控制元件,需要注意的是圖中紅框的部分from後面到資料夾,而不是具體的檔案,這種情況下預設是source/index.js 檔案。 接下來我們