重读《unix环境高级编程》-2012-10-16读书笔记

本文详细介绍了Unix环境下文件输入输出(I/O)操作的高级特性,包括Open函数的多种标志位作用、Creat函数的使用、Lseek的限制以及文件同步与原子读写操作。此外,还探讨了进程资源限制、Fork与Vfork函数的区别,以及进程控制中的times函数应用。最后,文章阐述了信号处理与线程的管理,包括清理函数的使用和线程的分离与回收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Unix环境高级编程(第二版)

第三章、文件IO

Open函数的O_APPEND为每次写时都追加到文件的尾端,此操作为原子操作,因此可以多进程同时以此标志打开进行写操作。

Open函数的O_CREAT与O_EXCL同时使用时,相当于测试文件是否存在,此操作为原子操作。

O_RSYNC: 使每一个以文件描述符作为参数的read操作等待,直到任何对文件同一部分进行的未决写操作都完成。

(比如,进程A在文件1的100字节处进行写操作,而进程B刚好正要在100字节处进行读操作,那么使用了该标志位以后,进行B会等待进行A的操作完成,以达到同步效果)

 

O_DSYNC: 使每次write操作等待物理IO操作完成,但是如果写操作并不影响读取写入的数据,则不等待文件属性被更新。

O_SYNC: 使每次write操作等待物理IO操作完成,包括由write操作引起的文件属性被更新所需的IO。

(区别:在重写现有文件内容时,O_DSYNC标志的操作并不会更新文件属性信息,但是O_SYNC标志的操作会更新文件属性,比如文件修改时间)

 

Creat函数不足之处在于只能以只写方式打开所创建的文件。可以使用

Open(filename, O_RDWR|O_CREAT|O_TRUNC,mode);

 

Lseek不能对管道、FIFO和网络套接字进行定位。

 

如何对文件进行原子读写操作?

1: O_APPEND标志打开

2. 使用原子函数preadpwrite函数。



其中的节点信息就是指:文件大小、文件创建、修改时间等等。

 

Dup和dup2函数复制一个新的文件描述符,但是两个文件描述符共享一个文件表,即当其中一个文件描述符使用lseek定位时,另一个文件描述符的当前文件偏移量也就变了。如下图所示:

 

Linux内核里有IO缓冲区,为了避免掉电时可以使用下面fsync(int fd)函数强制写入物理磁盘。

7章、环境变量

一个典型的C程序存储空间布局由以下几个部分组成: 
    
正文段CPU执行的指令部分,也就是主要的程序代码编译出来的结果,只读,通常可以共享。
    
初始化数据段:通常称之为数据段,包含了程序中需要明确赋值的变量,譬如一些初始化的全局变量等,如 int a = 10,变量名和值都存放在这个段中。
    
未初始化数据段:通常称之为BSSBlockStarted by Symbol)段,包含了程序中没有进行赋值的变量,譬如一些未初始化的全局变量,如 int a,在程序执行之前,内核会把这部分全部置为0NULL),
   
:自动变量以及每次函数调用时所需保存的信息放在此段中。如函数调用时要保存返回地址等。栈是从上向下分配的。
   
:通常在堆中进行动态存储分配,如malloc,calloc, realloc等都从这里面分配。堆是从下向上分配的。

   
通常堆顶和栈底之间的虚拟地址空间是很大的。
   
X86处理器上的Linux,正文段从0x08048000开始,栈底则从0xC0000000之下开始。

   
下图是一个典型的C程序存储空间的逻辑布局:
 

//main.cpp 
int a = 0;
全局初始化区 
char *p1;
全局未初始化区 
main() 

int b;
 
char s[] = "abc";
 
char *p2;
 
char *p3 = "123456"; 123456/0
在常量区,p3在栈上。 
static int c =0
全局(静态)初始化区 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 
分配得来得1020字节的区域就在堆区。 
strcpy(p1, "123456"); 123456/0
放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 
}

进程资源限制:

getrlimit和setrlimit函数。

Struct rlimit

{

       rlim_trlim_cur;   //软限制

       rlim_trlim_max;  //硬限制

}


 


第8章、进程控制

Fork函数之后父子进程的区别。




Vfork函数保证子进程先运行,直到子进程结束后才继续运行父进程.并且子进程和父进程共享数据。

 

进程cpu时间times函数,

Clock_ttimes(struct tms *buf);

Struct tms

{

Clock_ttms_utime;//用户cpu时间

Clock_t tms_stime;//系统cpu时间

Clock_ttms_cutime;//子进程用户cpu时间

Clock_ttms_sutime;//子进程系统cpu时间

}

 

10信号

被中断的系统调用处理方式:

again:

       if((n = read(fd, buf, BUFFSIZE)) <  0)

{

       if (errno = EINTR)

              goto again;

}

类似的函数还有ioctl/write/readv等

 

可重入函数:

是指在信号处理函数中调用函数的可靠性。


事实证明,在信号处理程序中调用一个不可重入的函数,则其结果是不可预见的。

 

第11章 线程

线程可以安排它退出时需要调用的函数,这个和进程可以使用atexit函数一样。处理程序记录的栈中,也就是说它们的执行顺序与它们注册时的顺序相反。

Void pthread_cleanup_push(void (*rtn)(void*), void *arg);

Void pthread_cleanup_pop(int execute);

如果execute参数设置为0,清理函数不被调用,但无论如何,都将删除上次push调用建立的清理处理程序。

这个函数有个限制,由于它们可以实现为宏,所以必须在于线程相同的作用域中以匹配的形式使用,push函数的宏定义可包括字符{,在这种情况下对应的匹配字符}就要在pop定义中出现。

在默认情况下,线程的终止状态会保存到对该线程调用pthread_join,如果线程已经处于分离状态,线程的底层存储资源可以在线程终止时立即收回。当线程被分离时,并不能用join函数等待它的状态终止,会被返回一个失败,返回EINVAL。Pthread_detach调用可以用于使线程处于分离状态。

Int pthread_detach(pthread_t tid);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值