unix环境高级编程 读书笔记
第8章
- exit和_exit区别:_exit会直接进入内核,不会关闭io流。进程基本控制函数还有:wait,fork,exec。
- atexit:程序正常退出时调用,如果因为signal退出则不能调用。功能:注册函数可以完成一些清理工作,比如全局log类,可以不设置析构函数,最后在atexit里删除它,防止它被调用时已经被析构。
- longjmp,跳转后,会恢复寄存器的值
- 每个进程都有父进程,如果父进程退出了,则他的父进id变为1,即init进程;如果子进程终止,父进程么有调用wait,则该进程变为僵尸进程;子进程终止,父进程会受到SIGCHLD信号,默认是选择忽略(在unix98和systemv下子进程也不会变成僵尸,但是posix规定需要调用wait);
- accton可以开启会计进程,统计进程的运行时数据;times可以获取当前cup时间和用户时间,是时间戳
第9章 - SIGTSTP信号可以使进程暂停,发送SIGCOUNT能使他继续运行
- 在终端输入CTRL+C会发送SIGINT信号,终止前台进程,但是当回话结束时,会发送SIGHUP,前端进程和所有向终端输出后的段进程都会终止
- SIGPIPE,如果对方关闭,发送方会受到一个RST响应报文报文,如果继续write,则会收到SIGPIPE信号。
第10章 - SIGSTOP和SIGKILL不可被捕捉和忽略
- 在慢系统调用阻塞过程中,如果进程捕捉到一个信号,就会中断系统调用,同时errno被设置为EINTR
- 可以屏蔽信号,既阻塞信号的投递
- sigsupend(mask),设置信号屏蔽为mask,并且挂起等待一个信号,直到信号触发后执行完处理程序。
第12章 - 低速系统调用:使系统永远阻塞,读写文件调用不属于这种;
- 多个进程写一个文件,可以加记录所recrod_lock
- dup2可以把一个文件句柄负债到标准输出,这样输出到屏幕的内容就写入文件了。
- 由fork产生的子进程不继承父进程的锁,因为一旦集成了,子进程就可以和父进程访问同一个文件了。
- 对于一个文件,fork产生的子进程和父进程公用一个文件表项,因为fd是一样的。这样父子进程共享文件位移;
dup 复制的fd,和原fd用用一个文件表项;
两次open同一个文件,返回的2个fd不公用一个文件表项 ,因为文件表项里有文件的打开标志和位移,这两次open是用不同的方式打开的,也有不同的文件位移,所以不能公用一个文件表项。 - 记录锁是挂在i节点上的,因此关闭文件句柄,该进程就会释放加在文件上的锁
- 可以用记录锁对一个文件加锁,从而做到一个程序只启动一个进程,该进程不管是否正常消亡,都会释放文件描述符从而释放锁。
- 建议性锁和强制性锁的区别。建议性锁只大家按照相同的规则去访问数据,比如都先try_lock 然后 write,最后un_lock,但是如果有进程不try_lock直接写文件破坏了规则,写乱了文件。
因此诞生了强制性锁,使用强制性锁需要打开文件的某些标志位。 - select 和poll 区别:poll不会破坏传入的ft_set参数
第14章 - pipe 创建的管道是半双工的,并且只能在具有共同祖先的进程间通讯。但是fifo,即命名管道可以在两个不相关的进程间通讯。
- fd = open() fp = fdopen(fp) fp = fileno(fd)
fp = fopen() - 引用pipe的进程全部终结时,pipe也被删除;但是fifo不会删除,虽然fifo中的内容已被删除掉,需要显示调用命令删除fifo; shm,msg,seg没有引用计数,会一直存在,直到用命令删除。
- 线程同步:
pthread_mutex_lock(&qlock) /lock/
pthread_cond_wait(&qready, &qlock) /block–>unlock–>wait()||(唤醒之后)return–>lock/
pthread_mutex_unlock(&qlock) /unlock/
pthread_cond_signal(&qready) 也最好放在lock和unlock之间,如果放在unlock后,可能锁会被另一个线程抢去,导致signal通知的线程获取不到锁进入等待状态。
第12章
- 进程id在系统中是唯一的,但是线程id只有在他所属的进程环境才有意义。
- 进程中任意线程调用exit或者_exit,都有导致整个进程退出。线程退出可以1)等线程函数执行完,2)或者调用pthread_exit(void *ptr),3)或者被其他线程取消pthread_cancel(threadid),该函数仅仅提出请求,并不等线程终结。
pthread_join(threadid, void**ptr1) 1)ptr执行返回码,2)ptr1指向ptr, 3)ptr指向内容为PTHREAD_CANCELED; - 1)线程调用pthread_exit(), 2)或者相应取消请求,3)或者用非0值调用pthread_cleanup_pop(execute)时,会触发调用由pthread_clean_push()压栈的清理函数。如果正常return,清理函数就不会被调用。
因为函数是压在栈上,所以 在push和pop之间如果有返回,相当于栈被破坏,所以一定要调用pthread_exit退出。 - pthread_detach(threadid),分离线程,分离后就不能调用pthread_join了,也不需要调用了,线程执行完系统会自动释放资源。
- pthread_mutex_init()
pthread_xxxatr_init()在完成初始化,并调用了pthread_mutex_init()后,需要调用pthread_xxxatr_destory()进行attr的释放。 - 当读写锁处于读模式pthread_rdlock_rdlock,有写锁尝试获取锁时,后续的读锁都会阻塞,防止读锁长期占用。
- 自旋锁(pthread_spin_lock)与互斥所差异:不会因为阻塞进入睡眠状态,而是一直忙等阻塞状态,这适合锁的持有时间段,并且不希望线程在重新调度上花费太多时间的状况。
- 用屏障pthread_barrier_wait()可以等待多个进程同时到达某个点。
- 如果一个函数可以被多个线程重入,就说这个函数是线程安全的(比如getenv不是线程安全),线程安全不代表异步信号处理程序重入是安全的。
如果为了线程安全,在getenv里加锁,而信号处理程序也调用了getenv这时候就会死锁,所以需要把锁设置为循环锁。 - 多个进程访问同一文件,可以用flockfile(File*),他是可以循环加锁的;注意它与记录锁的区别。
- errno是线程私有数据,不会被其他线程改写。
- 线程特定数据,键只需要创建一次,然后每个线程都能根据该键去读写自己的特定数据。
- 信号处理是程序是多个线程共享的,如果一个线程改了信号的处理方式,其他线程也会跟着改变。但是信号发生后是投递到单个线程的,如果信号与硬件故障有关,则投递给引起该信号的线程,其他情况下投递给任意线程。
- 如果多个线程调用sigwait处于阻塞状态,信号发生后,只有一个线程会从sigwait中返回。如果进程通过sigaction建立了信号处理函数。则与操作系统来决定是让sigwait返回,或者是调用信号处理函数。
- sigwait可以简化信号处理,化异步为同步:1)先设置信号屏蔽,会对所有线程生效,2)让一个线程调用sigwait,它会立刻解除阻塞并且等待信号发生,以后所有信号发生后都有该线程处理了。
- 调用pthread_create()创建的新线程继承调用者的信号屏蔽字,然后在新线程调用sigwait,这样新线程就成为了线程信号专用处理函数。
- pread是原子的,保证lseek和read同时执行。
第14章 -
- 调用close()关闭socket,接收缓冲区无数据,会给对方发送FIN标志,或者调用shutdown(SHUT_WR),发送完缓冲区数据后,会紧接着发送FIN标志
- 调用close()关闭socket,接收缓冲区有数据,直接给对方发送RST标志
- 调用close,前端收到FIN,read返回0;如果调用write,会收到rst错误,如果继续读会返回rst错误,继续写会发生epipe错误;收的rst后,如果继续读,会返回econnectrest错误
- sock_dgram套接字也可以调用connect,这样所有报文都发送给改地址,不需要再为每个数据报单独设置地址;同时也只能接受来自改地址的报文