本周主要是看代码,代码结构很烂,但是其中用的的技术却不少,比如:信号,多线程编程,socket网络编程和epoll事件轮询机制。而这些,恰好是我要学习的目标。正好利用此机会,边重构边学习。尽管我的重构水平遭到某同志的严重鄙视,但是,整体来说,收获也是不少的。期间,阅读了《UNIX环境高级编程》中的信号、线程部分,《UNIX网络编程》(第1卷)的socket编程通用函数部分、《代码大全》的变量命名部分。前两本的作者竟然是同一个人,其经典之作还有《TCP/IP协议详解》(三卷),不得不感叹W. Richard Stevens真是个计算机天才。
先说说信号,熟悉linux内核编程的人,对于信号这两个字应该是耳熟能详了。可以从以下三个方面理解信号:
1.为什么引入信号机制?
2.什么是信号?
3.如何处理信号?
为什么引入信号机制?计算机软件系统中所谓的信号,其实是一种异步事件处理方法。一般来说,进程不会时不时地主动去询问系统,是否发生了某种事件(如果这样,那进程就不用干别的有意义的事情了),而是当某事件发生时,系统主动发送信号通知进程。就好比,在学校里,学生一般不会主动跑去问班主任,今天学校发布了什么消息,而是学校发布消息时,班主任直接通知所有学生,或者通知班长告知大家。信号机制,也是如此。
什么是信号?计算机软件系统中的信号,其实就是一种软件中断技术,即一种系统通知进程某事件已经发生的技术。产生信号的原因很多,不同原因产生的信号 对应不同的信号名称,在计算机系统中,给每个信号名,分配了一个信号编号。根据信号编号,识别发生的事件。产生信号的原因举例:
比如:终端键盘输入,最熟悉的莫过于Ctrl+c了,都知道这两个组合键能够终止当前正在运行的进程。相对而言,知道 Ctrl + \ 的人就少了,其实这两个组合键是退出键,也能终止终止正在运行的进程。Ctrl+c对应SIGINT信号,Ctrl+\ 对应SIGQUIT信号。
再比如:调用函数abort(),kill(),alarm()等也能产生信号,abort()对应SIGABRT信号,kill()对应SIGKILL信号, alarm()对应SIGALRM()信号。
又比如:除0,非法访存等引起的硬件异常也能产生信号,除0对应SIGFPE信号,非法访存对应SIGSEGV信号。
通过上述例子,大家可看出一个规律,信号量以SIG这3个字符开头。事实上,这些信号量在头文件<signal.h>中定义,定义值是1--32的正整数。关于信号量的定义就不在此描述了。
如何处理信号?进程接收到信号后到底作何处理,就比如你接到一个命令后,你做如何响应,是对它莫不关心,置之不理,或是心不甘情不愿,被动接收,还是奋起反抗,提出异议。同样的,信号处理方式也分为三种:
1)忽略该信号 (SIG_IGN),就当信号不存在,完全不管。
2)默认动作(SIG_DFL),系统对每个信号都有一个默认动作。默认处理方式有:终止+core,终止,忽略。
3)捕捉该信号:自定义函数,信号发生时执行自定义的函数,即可按照自己希望的方式处理信号。
如果需要修改信号的默认处理动作,可通过函数:signal()和sigaction()实现,前者是早期版本,现在一般用后者实现。一般实现代码如下:
struct sigaction sa; sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, 0);
在如今这追求高效,高速的时代,计算机系统也毫不甘落后,从单核到多核,从多进程到多线程,无论从宏观数量上,还是微观粒度上都在竭力提高计算机的性能。同样,从三个方面理解多线程:
1.为什么引入多线程?
2.多线程编程的常用函数
3.多线程编程的技术难点
在计算机中运行的程序由进程组成,而进程又由线程组成。多线程编程,可以理解为是一种并行技术,将一个进程要完成的任务分给多个线程去做,那些彼此不想干,不会互相影响的线程就可以同时执行,从而提高系统性能。
多线程编程的常用函数:
1)设置线程属性(可选,非必须步骤)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)
2) pthread_create():创建线程(必须)
pthread_t tid;
pthread_create(&tid, &attr, (void *) my_function, NULL) ;// my_function:自定义线程执行的任务