概述 信号是一种软件中断,它提供了一种处理异步事件的方法,也是进程间惟一的异步通信方式。目前Linux信号不仅能告诉某一进程发生了什么事,还能给进程传递数据。 信号的来源 硬件方式 当用户在终端上按下某些键的时候,将产生信号,如CTRL+C组合键将产生SIGINT信号 硬件异常产生信号,如除数为0,无效的存储访问 软件方式 在终端下使用kill命令向进程发送任意信号 进程调用kill或sigqueue函数发送信号 当检测到某种软件条件已经具备时发出信号,由alarm或settimer设置的定时器超时将产生SIGALRM信号 信号的种类 在shell下输入kill-l可显示Linux系统支持的全部信号,如图: 信号的值在signal.h中定义,以上所有信号都有一定的含义,在此不一一陈述。 可靠信号与不可靠信号 在上图中,1号到31号之间的信号都是继承自UNIX系统,是不可靠的信号,33号到64号之间的信号都是可靠信号,也称为实时信号。 信号的可靠 继续阅读 >>


董恒毅 16/10/08 18:16:19
概述 进程间的通信,除过管道和命名管道之外,还有一种我认为是比上述两种方式更优秀的通信方式,那就是消息队列。 消息队列的基本概念 消息队列是一个存放在内核中的消息链表,每个消息队列是由消息读列标识符标识。它与之前两种进程间通信方式不同的就是,它是存在于内核之中的,只有在内核重启的时候或是显式的删除一个消息队列的时候,该消息队列才会真正的删除。 要操作消息队列,需要用到一些数据结构,熟悉并掌握这些数据结构对消息队列的理解是很重要的。 消息缓冲结构 向消息队列发送消息时,必须组成合理的数据结构。Linux定义了一个模板数据结构msgbuf。 #include<linux/msg.h> struct msgbuf { long mtype; char mtext[1]; }; //mtype表示的是消息类型,给消息指定类型,可以使消息在一个队列之中重复的使用。mtext指消息的内容。 注意: mtext虽然定义为char类型,但并不代表消息内容只能是一个字符,它是任意类型,它可以由用户定义。 继续阅读 >>


董恒毅 16/10/08 00:39:36
概述 对于进程间通信,由于管道的种种约束与不便,我们聪明的人类必然会想办法对其进行完善,以便使程序更加完美,然后就有了有名管道的诞生。 有名管道 有名管道也被称为FIFO,它的提出克制了管道在使用上面的不足,管道只能在有亲缘关系的进程间使用,而有名管道可以使不同的两个进程进行通信。 有名管道的实现原理 有名管道提供了一个路径名使之与自己关联,并且以FIFO的文件形式存储在文件系统中。有名管道就是一个设备文件,因此就算进程之间不存在 亲缘关系,只要访问该路径,就可以相互通信。由于FIFO是按照先进先出的原则工作,所以第一个被写入有名管道的数据总是第一个被读出。 有名管道的创建和读写 shell下创建有名管道 shell命令:mknod, mkfifo mknod用法:mknod Name { b | c } Major Minor b表示块文件,c表示字符文件。 后面第一个参数指定主设备数目,第二个参数指定次设备数目。 系统函数创建有名管道 #include&l 继续阅读 >>


董恒毅 16/10/07 22:59:54
概述 网络编程里面的套接虽然强大,但是使用起来比较麻烦,并且如果只是单机之中不同的进程间通信,那么我们就不需要用网络套接字进行编程,我们有更好的办法! 管道 管道是一种半双工的通信方式,所谓半双工,就是数据只能单方向的进行流动,好比设置管道一的一端为A口,另一端为B口,则数据只能由A流向B。除此之外,管道还只能在有亲缘关系的进程间使用,通常指父子进程。 管道的局限性 管道的局限性是比较多的,除了上述两个缺点之外,它还没有名字,它的缓冲区大小是受限制的,它传递的是无格式的字节流,因为这个缺陷,它得要求输入方和输出方事先约好数据的格式。基于种种不便,除了一些简单的进程间通信,我们基本是不使用管道的。 管道的实现原理 当用管道进行两个进程间的通信的时候,其实使用的是系统设置的文件描述符,也就是说,管道其实就是一个特殊的文件,但是这个文件只存在于内存之中,在创建管道的时候,系统为管道分配一个页面作为数据缓冲区,进行通信的两个进程就是通过读写这个缓冲区实现的。 管道的创建和读写 #include< 继续阅读 >>


董恒毅 16/09/29 22:34:32
一。互斥量和条件变量简介 互斥量(mutex)从本质上说是一把锁,在访问共享资源前对互斥量进行加锁,在访问完成后释放互斥量上的锁。对互斥量进行加锁以后,任何其他试图再次对互斥锁加锁的线程将会阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为运行状态的线程可以对互斥锁加锁,其他线程将会看到互斥锁依然被锁住,只能回去再次等待它重新变为可用。 条件变量(cond)是在多线程程序中用来实现”等待–》唤醒”逻辑常用的方法。条件变量利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使“条件成立”。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。线程在改变条件状态前必须首先锁住互斥量,函数pthread_cond_wait把自己放到等待条件的线程列表上,然后对互斥锁解锁(这两个操作是原子操作)。在函数返回时,互斥量再次被锁住。 二。为什么存在条件变量 首先,举个例子:在应用程序中有连个线 继续阅读 >>


董恒毅 16/08/04 15:58:28
这几天看了一点进程的知识,也会创建一个或几个子进程了,在这里,我很想和大家分享一下,在创建子进程的时候,我们现在所说的写时拷贝技术。 我们知道,在我们fork一个进程之后,系统就会给我们创建一个子进程,此时,子进程会继承父进程几乎所有的资源,并且系统会给子进程分配一个新的物理空间,但实际上,子进程和父进程是用的同一个代码段的,在fork之后子进程只是复制了父进程的数据段,堆栈段,但即使这样,也还是会浪费系统的资源空间,之后,fork做了这样的改变,父进程在fork完之后,子进程只是有了自己的独立虚拟空间,它的物理空间其实是和父进程共享的,当系统检测到父进程和子进程的相应段发生变化的时候,也就是有写的操作的时候,系统才给子进程分配相应的物理空间。 我们也许会问,为什么有写时拷贝这样的技术,这样做的用处是什么,你可以想想,当我们fork一个程序之后,如果立马使用了exec函数族,那么如果还像以前那样,fork完之后就复制父进程的资源给子进程,但是子进程根本用不到这些代码和数据,那么系统的资源就会被浪费,unix和unix(like)是非常讲究效率的操作 继续阅读 >>


董恒毅 16/08/01 21:00:55
等待进程结束 当子进程先于父进程退出时,如果父进程没有调用wait和waitpid函数,子进程就会进入僵尸状态 #include<sys/types.h> #include<sys/wait.h> pid_t wait(int *statloc) pid_t waitpid(pid_t pid, int *statloc, int options) //wait函数的返回值是终止运行的子进程的pid,参数statloc存放的是子进程的退出码,状态信息将被写入statloc所指向的变量 //wait函数也会来等待子进程的结束,但它用于等待某个特定的子进程的pid,statloc和wait的含义相同,option如果被设置为WNOHANG,则父进程不被挂起而立即执行后面的代码 如果想让父进程周期性的检查某个特定子进程是否退出,可以写如下代码: waitpid(child pid, (int *)0, WNOHANG) 如果子进程未退出则返回0,子进程已经结束,返回childpid,失败返回-1 进程的其他操作 继续阅读 >>


董恒毅 16/08/01 17:41:39
进程退出 在Linux下系统进程退出的方法分为正常退出和异常退出两种 正常退出: 在main函数中执行return 调用exit函数 调用_exit函数 异常退出: 调用abort函数 进程收到某个信号,而该信号使程序终止 补充: exit和return的区别:exit是将控制权交给系统,return将控制权交给函数 exit和abort的区别:exit是正常终止,abort是异常终止 exit(int exit_code):exit中的参数为0代表正常终止,若为其他值表示异常终止 exit和_exit的区别:exit在stdlib.h中声明,而_exit在unistd.h中声明,exit要先执行一些清除操作,然后将控制权交给内核,而_exit会执行后立即返回给内核 僵尸进程: 当父进程先于子进程退出,子进程会变成孤儿进程而被init收养,当子进程先于父进程退出,父进程还没有调用wait函数等待的话,子进程就会变成僵尸进 继续阅读 >>


董恒毅 16/07/30 16:02:48
进程操作 1. 创建进程: 系统创建:由它创建的进程是平等的,一般不会存在资源继承的关系,在系统启动时,操作系统会创建一些进程,他们承担着管理和分配系统资源的任务,这些进程也被称为系统进程。 父进程创建:子进程和父进程属于隶属关系,子进程也可以继续创建子进程,这样就会形成一个进程家族。子进程会继承父进程几乎所有的系统资源。接下来讲的都是父进程创建子进程。 2.fork函数: #include<sys/types.h> #include<unistd.h> int fork() //fork函数非常特殊,它有两个返回值。当fork调用后,当前进程实际上就已经分裂成两个进程,一个是父进程,一个是刚刚创建的子进程,fork函数的两个返回值分别是父进程调用fork函数返回子进程的进程id,一个是子进程调用fork函数返回0,一般会在程序中用这两个返回值来判断当前是哪个进程在执行这个程序。 //进程创建失败会返回-1。 补充: fork函数之后到底是子进程先运行,还是父进程先运行这是不确定的,它 继续阅读 >>


董恒毅 16/07/30 10:27:41
linux进程: 今天准备开始总结linux进程的相关知识,我会从进程的概念入手,给大家总结完进程结构,进程的内存映像,如何创建进程,退出进程,在进程中执行新程序,以及如何获取进程ID,改变进程优先级等等 进程概念: //首先,我们知道,一个电脑能正常运行,除了电源和必备的硬件之外,最重要的就属操作系统了,操作系统是用来管理计算机的软,硬件资源,使一台计算机能真正的运行起来,而现代的操作系统的主要特点就在于程序的并行执行(简单说就是多个逻辑上独立的程序或程序段可以同时进行),然后就需要借助进程这个东西了。 //进程是管理系统资源的最小单位,linux可以同时启动多个进程。 //进程是程序执行的一次过程,进程和程序,线程都是不一样的,进程是动态的,程序是静态的,进程是运中的程序,程序是保存在硬盘上的可执行代码。 进程标识: 每个进程都是通过唯一的进程id进行标识的,它是一个非负整数,每个进程还有一些其他的标识,这些都可以用函数来获得。 int getpid(): 获得进程id int getppid(): 获得父 继续阅读 >>


董恒毅 16/07/29 11:53:17