1:管道:×管道可以在同组进程通讯。如果要在不同组进程间用管道通讯,那么要用FIFO。 --数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。 --如果没有读进程,那么管道的写操作就会失败 --管道写端和读端的声明:int pipe_fd[2]; pipe()的调用必须在fork之前 --管道的读是在文件的头部,写是在文件的尾部写入。所以声明int pipe_fd[2]后,使用的时候惯例是把pipe_fd[1]作为写端的标识符,pipe_fd[0]作为读端的标志符号。 --应为管道是半双功的,为了保证操作的原子性,写的时候必须要事读端关闭;读的时候必须保证写端关闭。 2:FIFO:很好地解决在无关进程间数据交换的要求 -- int mkfifo( const char * filename, mode_t mode ); pathname:FIFO文件名 mode:文件属性 --shell命令:mkfifo 3:volatile sig_atomic_t quitflag; 这样声明可以保证变量在使用或赋值时,无论在32或64位的机器上都能保证操作的原子性,它会根据机器的类型自动适应。 4:IPC共享内存:两个或多个进程访问公共数据块; --共享内存请求的数据块大小一般都是4096的整数倍。如果请求是1024,内核也只会分配率4096的数据块大小。所以为了不产生浪费,建议使用4096的整数倍。 --shmget():获得一个共享内存的IPC标志符,如果这个共享内存不存在,就创建她。 shmat():把一个共享内存段attach到一个进程上。 shmdt():detach有IPC所指定的共享内存段。 --key_t ftok(char * name,int id);name必须是一个已经存在的文件。在有些操作系统下,name文件作了修改或者name改变了(这事应为操作系统对文件系统管理不一样造成的),那么inode也会改变;所以在使用ftok时,文件修改力,那么要重启程序。 ×--ls -i 可以看文件的inode 5:程序收到信号后,如果不对信号处理,就会导致程序退出,但如果程序捕获信号进行处理,按照它的逻辑,它是不一定会退出的。在这三个信号中,sigkill是不能被捕获的,程序收到这个信号后,一定会退出。这就是kill -9一定能保证将程序杀死的原因。 --信号 产生方式 对进程的影响 sigint 通过ctrl+c将会对当进程发送此信号 信号被当前进程树接收到,也就是说,不仅当前进程会收到信号,它的子进程也会收到; --SIGTERM。与SIGKILL不同的是该信号可以被阻塞和处理。通常要求程序退出的时候用到。shell的kill命令缺省产生这个信号。 6:一个进程仅存在给定类型的一个挂起信号,同一进程同样类型的其他不被排队。 7:int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 功能描述:设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。 参数: how:用于指定信号修改的方式,可能选择有三种 SIG_BLOCK //加入信号到进程屏蔽。 SIG_UNBLOCK //从进程屏蔽里将信号删除。 SIG_SETMASK //将set的值设定为新的进程屏蔽。 set:为指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。 oldset:也是指向信号集的指针,在此存放原来的信号集。 返回说明: 成功执行时,返回0。失败返回-1,errno被设为EINVAL。 例子:sigprocmask(SIG_BLOCK,&newmask,&oldmask);//把newmask中的SIGQUIT信号阻塞,并把当前放到oldmask中 sigprocmask(SIG_SETMASK,&oldmask,NULL);恢复原来的信号集T(这个信号即是oldmask) 8:sigsuspend的使用 sigprocmask和pause连起来用可以实现sigsuspend的功能;但是还是使用sigsuspend函数,应为sigsuspend是原子操作。 sigsuspend是一个原子操作,包含4个步骤: (1) 设置新的mask阻塞当前进程; (2) 收到信号,恢复原先mask; (3) 调用该进程设置的信号处理函数; (4) 待信号处理函数返回后,sigsuspend返回。 9:getppid()得到父进程pid,getpid()得到本进程pid。 10:--signal(SIGINT,catcher);当接到SIGINT的时候,调用catcher函数. sigaction(SIGUSR1,&user_action,NULL);//设置信号处理函数 第一个函数和第二个结构都可以设置信号处理函数 --sigpending得到挂起信号集合 --sigismember检查挂起信号集合中是否有SIGQUIT --sigaddset添加信号 --系统的信号有31个,其中用户可以自定义的信号只有两个:SIGUSR1和SIGUSR2 11:--所有的进程祖先是进程0 --进程1:由进程0创建的内核线程执行init()函数,init()四次轮流调用kernel_thread()函数为常规内核任务初始化四个必要的内核线程。init()调用execve()系统调用装入可执行程序init。因此init内核线程变成一个普通的进程,它拥有自己的内核数据结构。init进程从不终止,因为它创建和监控操作系统外层的所有进程活动。这也就是为什么僵死进程最后由它来处理。 12:僵死进程:在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill -9也不能杀死僵尸进程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程。 --利用命令ps,可以看到有标记为Z的进程就是僵尸进程 --怎样来清除僵尸进程: 1.改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。 2.把父进程杀掉。父进程死后,僵尸进程成为"孤儿进程",过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。 --SIGCHLD SIGCHLD属于unix以及类unix系统的一种信号 产生原因 siginfo_t代码值 1,子进程已终止 CLD_EXITED 2,子进程异常终止(无core) CLD_KILLED 3,子进程异常终止(有core) CLD_DUMPED 4,被跟踪子进程以陷入 CLD_TRAPPED 5,子进程已停止 CLD_STOPED 5,停止的子进程已经继续 CLD_CONTINUED 描述: 在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程。按系统默认将忽略此信号。如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。信号的捕捉函数中通常调用wait函数以取得进程ID和其终止状态 13:Makefile 规则:用于说明如何生成一个或多个目标文件, 规则:用于说明如何生成一个或多个目标文件, 规则格式如下: targets : prerequisites command 目标 依赖 命令 main.o : main.c gcc –c main.c 目标?依赖?命令? 命令需要以【 **命令需要以 【TAB】键开始 ** --Makefile中只应该有一个最终目标 --第一条规则中的目标将被确立,但是第一条规则中的目标将被确立为最终的目标。 --Makefile中把那些 没有任何依赖只有执行 动作的目标 称为“伪目标 ”(phony 动作的目标称为 targets)。 .PHONY : clean clean : rm –f hello main.o func1.o func2.o “.PHONY” 将“clean”目标声明为伪目标 14:线程同步 进行多线程编程,因为无法知道哪个线程会在哪个 时候对共享资源进行操作,因此让如何保护共享资 源变得复杂,通过下面这些技术的使用,可以解决 线程之间对资源的竞争: 1. 互斥量Mutex 2. 信号灯Semaphore 3. 条件变量Conditions --互斥量 对于这种情况,系统给我们提供了互斥量。 线程在取出头节点前必须要等待互斥量,如 果此时有其他线程已经获得该互斥量,那么 该线程将会阻塞在这里。只有等到其他线程 释放掉该互斥量后,该线程才有可能得到该 互斥量。互斥量从本质上说就是一把锁, 提供 对共享资源的保护访问 --加锁 对共享资源的访问, 要使用互斥量进行加锁, 如果互斥量已经上了 锁, 调用线程会阻塞, 直到互斥量被解锁。 v int pthread_mutex_lock(pthread_mutex_t *mutex) v int pthread_mutex_trylock(pthread_mutex_t *mutex) 返回值: 成功则返回0, 出错则返回错误编号。 trylock是非阻塞调用模式, 如果互斥量没被锁住, trylock函数将对互 斥量加锁, 并获得对共享资源的访问权限; 如果互斥量被锁住了, trylock函数将不会阻塞等待而直接返回EBUSY, 表示共享资源处于 忙状态。 --解锁 在操作完成后,必须给互斥量解锁,也就 是前面所说的释放。这样其他等待该锁的 线程才有机会获得该锁,否则其他线程将 会永远阻塞。 int pthread_mutex_unlock(pthread_mutex_t *mutex) --互斥量PK信号量 Mutex是一把钥匙,一个人拿了就可进入一个房 间,出来的时候把钥匙交给队列的第一个。 Semaphore是一件可以容纳N人的房间,如果人不 满就可以进去,如果人满了,就要等待有人出来。 对于N=1的情况,称为binary semaphore。 Binary semaphore与Mutex的差异: 1. mutex要由获得锁的线程来释放(谁获得,谁释 放)。而semaphore可以由其它线程释放 2. 初始状态可能不一样:mutex的初始值是1 ,而 semaphore的初始值可能是0(或者为1)。
linux 读书笔记
最新推荐文章于 2021-05-25 18:35:55 发布