① linux驱动模块中添加异步通知机制需要完成哪些工作
一 驱动方面:
1. 在设备抽象的数据结构中增加一个struct fasync_struct的指针
2. 实现设备操作中的fasync函数,这个函数很简单,其主体就是调用内核的fasync_helper函数。
3. 在需要向用户空间通知的地方(例如中断中)调用内核的kill_fasync函数。
4. 在驱动的release方法中调用前面定义的fasync函数
呵呵,简单吧,就三点。其中fasync_helper和kill_fasync都是内核函数,我们只需要调用就可以了。在1中定义的指针是一个重要参数,fasync_helper和kill_fasync会使用这个参数。
二 应用层方面
1. 利用signal或者sigaction设置SIGIO信号的处理函数
2. fcntl的F_SETOWN指令设置当前进程为设备文件owner
3. fcntl的F_SETFL指令设置FASYNC标志
完成了以上的工作的话,当内核执行到kill_fasync函数,用户空间SIGIO函数的处理函数就会被调用了。
呵呵,看起来不是很复杂把,让我们结合具体代码看看就更明白了。
先从应用层代码开始吧:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define MAX_LEN 100
//处理函数,没什么好讲的,用户自己定义
void input_handler(int num)
{
char data[MAX_LEN];
int len;
//读取并输出STDIN_FILENO上的输入
len = read(STDIN_FILENO, &data, MAX_LEN);
data[len] = 0;
printf("input available:%s\n", data);
}
void main()
{
int oflags;
//启动信号驱动机制,将SIGIO信号同input_handler函数关联起来,一旦产生SIGIO信号,就会执行input_handler
signal(SIGIO, input_handler);
//STDIN_FILENO是打开的设备文件描述符,F_SETOWN用来决定操作是干什么的,getpid()是个系统调用,
//功能是返回当前进程的进程号,整个函数的功能是STDIN_FILENO设置这个设备文件的拥有者为当前进程。
fcntl(STDIN_FILENO, F_SETOWN, getpid());
//得到打开文件描述符的状态
oflags = fcntl(STDIN_FILENO, F_GETFL);
//设置文件描述符的状态为oflags | FASYNC属性,一旦文件描述符被设置成具有FASYNC属性的状态,
//也就是将设备文件切换到异步操作模式。这时系统就会自动调用驱动程序的fasync方法。
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后进入一个死循环,程序什么都不干了,只有信号能激发input_handler的运行
//如果程序中没有这个死循环,会立即执行完毕
while (1);
}
再看驱动层代码,驱动层其他部分代码不变,就是增加了一个fasync方法的实现以及一些改动
//首先是定义一个结构体,其实这个结构体存放的是一个列表,这个
//列表保存的是一系列设备文件,SIGIO信号就发送到这些设备上
static struct fasync_struct *fasync_queue;
//fasync方法的实现
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
//将该设备登记到fasync_queue队列中去
retval=fasync_helper(fd,filp,on,&fasync_queue);
if(retval<0)
{
return retval;
}
return 0;
}
在驱动的release方法中我们再调用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
//..processing..
drm_fasync(-1, filp, 0);
//..processing..
}这样后我们在需要的地方(比如中断)调用下面的代码,就会向fasync_queue队列里的设备发送SIGIO信号
,应用程序收到信号,执行处理程序
if (fasync_queue)
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
② 当linux应用程序中存在多个异步通知时怎样处理
驱动程序运行在内核空间中,应用程序运行在用户空间中,两者是不能直接通信的。但在实际应用中,在设备已经准备好的时候,我们希望通知用户程序设备已经ok,用户程序可以读取了,这样应用程序就不需要一直查询该设备的状态,从而节约了资源,这就是异步通知。好,那下一个问题就来了,这个过程如何实现呢?简单,两方面的工作。
一 驱动方面:
1. 在设备抽象的数据结构中增加一个struct fasync_struct的指针
2. 实现设备操作中的fasync函数,这个函数很简单,其主体就是调用内核的fasync_helper函数。
3. 在需要向用户空间通知的地方(例如中断中)调用内核的kill_fasync函数。
4. 在驱动的release方法中调用前面定义的fasync函数
呵呵,简单吧,就三点。其中fasync_helper和kill_fasync都是内核函数,我们只需要调用就可以了。在
1中定义的指针是一个重要参数,fasync_helper和kill_fasync会使用这个参数。
二 应用层方面
1. 利用signal或者sigaction设置SIGIO信号的处理函数
2. fcntl的F_SETOWN指令设置当前进程为设备文件owner
3. fcntl的F_SETFL指令设置FASYNC标志
完成了以上的工作的话,当内核执行到kill_fasync函数,用户空间SIGIO函数的处理函数就会被调用了。
呵呵,看起来不是很复杂把,让我们结合具体代码看看就更明白了。
先从应用层代码开始吧:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#define MAX_LEN 100
//处理函数,没什么好讲的,用户自己定义
void input_handler(int num)
{
char data[MAX_LEN];
int len;
//读取并输出STDIN_FILENO上的输入
len = read(STDIN_FILENO, &data, MAX_LEN);
data[len] = 0;
printf("input available:%s\n", data);
}
void main()
{
int oflags;
//启动信号驱动机制,将SIGIO信号同input_handler函数关联起来,一旦产生SIGIO信号,就会执行input_handler
signal(SIGIO, input_handler);
//STDIN_FILENO是打开的设备文件描述符,F_SETOWN用来决定操作是干什么的,getpid()是个系统调用,
//功能是返回当前进程的进程号,整个函数的功能是STDIN_FILENO设置这个设备文件的拥有者为当前进程。
fcntl(STDIN_FILENO, F_SETOWN, getpid());
//得到打开文件描述符的状态
oflags = fcntl(STDIN_FILENO, F_GETFL);
//设置文件描述符的状态为oflags | FASYNC属性,一旦文件描述符被设置成具有FASYNC属性的状态,
//也就是将设备文件切换到异步操作模式。这时系统就会自动调用驱动程序的fasync方法。
fcntl(STDIN_FILENO, F_SETFL, oflags | FASYNC);
//最后进入一个死循环,程序什么都不干了,只有信号能激发input_handler的运行
//如果程序中没有这个死循环,会立即执行完毕
while (1);
}
再看驱动层代码,驱动层其他部分代码不变,就是增加了一个fasync方法的实现以及一些改动
//首先是定义一个结构体,其实这个结构体存放的是一个列表,这个
//列表保存的是一系列设备文件,SIGIO信号就发送到这些设备上
static struct fasync_struct *fasync_queue;
//fasync方法的实现
static int my_fasync(int fd, struct file * filp, int on)
{
int retval;
//将该设备登记到fasync_queue队列中去
retval=fasync_helper(fd,filp,on,&fasync_queue);
if(retval<0)
{
return retval;
}
return 0;
}
在驱动的release方法中我们再调用my_fasync方法
int my_release(struct inode *inode, struct file *filp)
{
//..processing..
drm_fasync(-1, filp, 0);
//..processing..
}
这样后我们在需要的地方(比如中断)调用下面的代码,就会向fasync_queue队列里的设备发送SIGIO信号
,应用程序收到信号,执行处理程序
if (fasync_queue)
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
好了,这下大家知道该怎么用异步通知机制了吧?
以下是几点说明[1]:
1 两个函数的原型
int fasync_helper(struct inode *inode, struct file *filp, int mode, struct fasync_struct **fa);
一个"帮忙者", 来实现 fasync 设备方法. mode 参数是传递给方法的相同的值, 而 fa 指针指向一个设
备特定的 fasync_struct *
void kill_fasync(struct fasync_struct *fa, int sig, int band);
如果这个驱动支持异步通知, 这个函数可用来发送一个信号到登记在 fa 中的进程.
2.
fasync_helper 用来向等待异步信号的设备链表中添加或者删除设备文件, kill_fasync被用来通知拥有相关设备的进程. 它的参数是被传递的信号(常常是 SIGIO)和 band, 这几乎都是 POLL_IN[25](但是这可用来发送"紧急"或者带外数据, 在网络代码里).
③ Linux开发需要什么呢需要具备什么基础呢
一、linux和os:
1、命令:netstat tcpmp ipcs ipcrm 这四个命令的熟练掌握程度基本上能体现实际开发和调试程序的经验
2、cpu 内存 硬盘 等等与系统性能调试相关的命令必须熟练掌握,设置修改权限 tcp网络状态查看 各进程状态 抓包相关等相关命令 必须熟练掌握
3、awk sed需掌握
4、共享内存的使用实现原理、然后共享内存段被映射进进程空间之后,存在于进程空间的什么位置?共享内存段最大限制是多少?
5、c++进程内存空间分布(注意各部分的内存地址谁高谁低,注意栈从高道低分配,堆从低到高分配)
6、ELF是什么?其大小与程序中全局变量的是否初始化有什么关系(注意.bss段)
7、使用过哪些进程间通讯机制,并详细说明
8、makefile编写,虽然比较基础,但是会被问到
9、gdb调试相关的经验,会被问到
10、如何定位内存泄露?
11、动态链接和静态链接的区别
12、32位系统一个进程最多多少堆内存
13、多线程和多进程的区别(重点 必须从cpu调度,上下文切换,数据共享,多核cup利用率,资源占用,等等各方面回答,然后有一个问题必须会被问到:哪些东西是一个线程私有的?答案中必须包含寄存器,否则悲催)
14、写一个c程序辨别系统是64位 or 32位
15、写一个c程序辨别系统是大端or小端字节序
16、信号:列出常见的信号,信号怎么处理?
17、i++是否原子操作?并解释为什么???????
18、说出你所知道的各类linux系统的各类同步机制(重点),什么是死锁?如何避免死锁(每个技术面试官必问)
19、列举说明linux系统的各类异步机制
20、exit() _exit()的区别?
21、如何实现守护进程?
22、linux的内存管理机制是什么?
23、linux的任务调度机制是什么?
24、标准库函数和系统调用的区别?
25、补充一个问题:系统如何将一个信号通知到进程?
二、c语言:
1、宏定义和展开(必须精通)
2、位操作(必须精通)
3、指针操作和计算(必须精通)
4、内存分配(必须精通)
5、各类库函数必须非常熟练的实现
6、哪些库函数属于高危函数,为什么?(strcpy等等)
三、c++:
1、一个String类的完整实现必须很快速写出来(注意:赋值构造,operator=是关键)
2、虚函数的作用和实现原理(必问必考,实现原理必须很熟)
3、sizeof一个类求大小(注意成员变量,函数,虚函数,继承等等对大小的影响)
4、指针和引用的区别(一般都会问到)
5、多重类构造和析构的顺序
6、stl各容器的实现原理(必考)
7、extern c 是干啥的,(必须将编译器的函数名修饰的机制解答的很透彻)
8、volatile是干啥用的,(必须将cpu的寄存器缓存机制回答的很透彻)
9、static const等等的用法,(能说出越多越好)
四、数据结构或者算法:
1、《离散数学》范围内的一切问题皆由可能被深入问到(最重要,最体现功底,最能加分,特别是各类树结构的实现和应用)
2、各类排序:大根堆的实现,快排(如何避免最糟糕的状态?),bitmap的运用等等
3、hash, 任何一个技术面试官必问(例如为什么一般hashtable的桶数会取一个素数?如何有效避免hash结果值的碰撞)
五、网络编程:
1、tcp与udp的区别(必问)
2、udp调用connect有什么作用?
3、tcp连接中时序图,状态图,必须非常非常熟练
4、socket服务端的实现,select和epoll的区别(必问)
5、epoll哪些触发模式,有啥区别?(必须非常详尽的解释水平触发和边缘触发的区别,以及边缘触发在编程中要做哪些更多的确认)
6、大规模连接上来,并发模型怎么设计
7、tcp结束连接怎么握手,time_wait状态是什么,为什么会有time_wait状态?哪一方会有time_wait状态,如何避免time_wait状态占用资源(必须回答的详细)
8、tcp头多少字节?哪些字段?(必问)
9、什么是滑动窗口(必问)
10、connect会阻塞,怎么解决?(必考必问,提示:设置非阻塞,返回之后用select检测状态)
11、如果select返回可读,结果只读到0字节,什么情况?
12、keepalive 是什么东东?如何使用?
13、列举你所知道的tcp选项,并说明其作用。
14、socket什么情况下可读?
六、db:
1、mysql,会考sql语言,服务器数据库大规模数据怎么设计,db各种性能指标
④ linux同步io和异步io的区别
异步文件IO也就是重叠IO。
在同步文件IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行。而异步文件IO方式中,线程发送一个IO请求到内核,然后继续处理其他的事情,内核完成IO请求后,将会通知线程IO操作完成了。
如果IO请求需要大量时间执行的话,异步文件IO方式可以显着提高效率,因为在线程等待的这段时间内,CPU将会调度其他线程进行执行,如果没有其他线程需要执行的话,这段时间将会浪费掉(可能会调度操作系统的零页线程)。如果IO请求操作很快,用异步IO方式反而还低效,还不如用同步IO方式。
同步IO在同一时刻只允许一个IO操作,也就是说对于同一个文件句柄的IO操作是序列化的,即使使用两个线程也不能同时对同一个文件句柄同时发出读写操作。重叠IO允许一个或多个线程同时发出IO请求。
⑤ 请问linux下C编程多线程同步和异步的区别,如何能实现程序的同步和异步编程
同步就是使得两个或者多个进程之间的行为按照一定的时序来执行。比如说线程A完成了某件事,然后线程B才能做某件事。具体一点,就是,线程间的某个动作执行前需要确认一个或者多个其他线程的当前状态。而异步则是多个线程各跑各的,互不干涉。
Linux下的多线程实现由pthread库提供,头文件为pthread.h。多线程最重要的就是要保护好共享资源(用互斥体,mutex),尤其是异步。代码哥哥就不上了,这里关键的不是代码的问题,也不是Linux、Windows的问题,重要的是概念的理解。哥们不妨先研究研究“生产者-消费者”这个常出现在教科书上的模型,这是一个典型的同步问题。就讲这么多了,拜拜。
⑥ 简单说明+Linux+系统中信号的处理方式。+(说出一种给1分举例说明再加2分)
摘要 遇到问题一定要控制好自己的情绪,不要发火,不要偏激,不要说话太伤人,要懂得忍耐,忍耐不是为了让你不去处理这件事情,而是为了避免在情绪失控的情况下,做出充动让自己永远后悔的事情。用心去体会,礼貌做人,踏实做事,放大格局,调整心态,把握当下,快乐生活每一天!谢谢!
⑦ Linux中同步信号和异步信号分别怎么解释
Linux异步信号
1.int pthread_kill(pthread_t threadid, intsigno);
向特定的线程发送信号signo
2.int pthread_sigmask(int how, const sigset_t*newmask, sigset_t *oldmask);
设置线程的信号屏蔽码
3.int sigwait(const sigset_t *set, int *sig);
阻塞线程,等待set中指定的信号之一到达,并将到达的信号存入*sig。
4.代码
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
//#define SIGUSRR 40;
int SIGUSRR = 40;
void* threadOne(void *arg)
{
sigset_tsigset;
intsigno;
sigemptyset(&sigset);
sigaddset(&sigset,SIGUSRR);
pthread_sigmask(SIG_BLOCK,&sigset, NULL);
while(1)
{
sigwait(&sigset,&signo);
printf("getthread cond sig!\n");
}
}
int main(int argc, char **argv)
{
if(argc != 1)
{
printf("Usage:\n");
printf("threadcond\n");
return1;
}
pthread_tthreadId;
if(pthread_create(&threadId,NULL, threadOne, NULL) != 0)
{
printf("threadcreate error! \n");
return1;
}
//structsigaction act;
//act.sa_handler=SIG_IGN;
//sigemptyset(&act.sa_mask);
//act.sa_flags=0;
//sigaction(SIGUSRR,&act,0);//设置信号SIGUSR1的处理方式忽略
usleep(1000000);
pthread_kill(threadId,SIGUSRR);
usleep(1000000);
pthread_kill(threadId,SIGUSRR);
usleep(2000000);
return0;
}
⑧ 在Linux中我还是理解不了同步和异步,求解释
打个比方,你现在要做两件事,一件事是烧水,一件事是晾衣服。所谓的同步就是指:你必须等水烧开了再去晾衣服。所谓的异步就是指在烧水的过程中,你完全可以再去晾衣服。所以,引入异步机制其实就是为了提高效率。当然,有的时候,如果两件事之间有依赖性,那么就是无法异步的,比如烧水和喝水,这两件事是没法异步去做的。
⑨ 在设Linux在设备驱动和应用程序的异步通知交互中,在设备驱动程序中增加信号释放的作用是
在设备驱动和应用程序的异步通知交互中,仅仅在应用程序端捕获信号是不够的,因为信号的源头在设备驱动端。因此,应该在合适的时机让设备驱动释放信号,在设备驱动程序中增加信号释放的相关代码。为了使设备支持异步通知机制,驱动程序中涉及3项工作。
1)支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。不过此项工作已由内核完成,设备驱动无须处理。
2)支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的fasync()函数将得以执行。因此,驱动中应该实现fasync()函数。
3)在设备资源可获得时,调用kill_fasync()函数激发相应的信号。
驱动中的上述3项工作和应用程序中的3项工作是一一对应的,设备驱动中异步通知编程比较简单,主要用到一项数据结构和两个函数。数据结构是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结构体指针放在设备结构体中仍然是最佳选择。
在设备驱动的fasync()函数中,只需要简单地将该函数的3个参数以及fasync_struct结构体指针的指针作为第4个参数传入fasync_helper()函数即可。
在设备资源可以获得时,应该调用kill_fasync()释放SIGIO信号。在可读时,第3个参数设置为POLL_IN,在可写时,第3个参数设置为POLL_OUT。
⑩ Linux中异步IO模型有哪些
1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)
3) I/O复用(select 和poll) (I/O multiplexing)
4)信号驱动I/O (signal driven I/O (SIGIO))
5)异步I/O (asynchronous I/O (the POSIX aio_functions))
其中前4种都是同步,最后一种才是异步。