码迷,mamicode.com
首页 > 其他好文 > 详细

《unix环境高级编程》 读书笔记 (1)

时间:2014-09-05 12:59:41      阅读:331      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   os   io   使用   ar   for   



近来读书,做些笔记,来年好翻翻。

本文所使用的操作系统为 CentOS7.0,如果不想装双系统的可以装虚拟机,可以参考这里:

http://blog.csdn.net/alex_my/article/details/38142229

当然啦,直接装个再好不过了。

File I/O


1 file descriptor

// 查看当前session中的fd数量限制 
ulimit -n

// 修改当前session中的fd数量限制
ulimit -n your_need

可以在一个终端使用以上命令,另外再打开一个进行查看。

在程序中,可以使用系统函数进行修改
#include <sys/resource.h>

struct rlimit
{
     rlim_t rlim_cur;
     rlim_t rlim_max;
}

int getrlimit(int resource, struct rlimit* rlim);
int setrlimit(int resource, const struct rlimit* rlim);

ext:

resource可选择的有:

RLIMIT_CORE: 设置core文件的大小,0表示禁止创建core文件。一个程序崩溃的时候,会在指定目录生成一个core文件,主要是用于调试。

RLIMIT_CPU: 设置每秒内的cpu Time,如果超过这个限制,则会发送SIGXCPU信号。

RLIMIT_DATA: 设置进程中data segment大小,单位为bytes。如果超过这个限制,malloc()会失败。具体关于data segment 参考这里: http://blog.csdn.net/fatshaw/article/details/6294557

RLIMIT_FSIZE: 设置进程内文件最大长度,如果超过这个长度,则产生SIGXFSZ信号。如果线程阻塞,或者进程抓取或者忽略了这个信号,则会从底部减少文件大小并设置EFBIG错误。

RLIMIT_NOFILE: 设置文件描述符大小,比最大文件描述符大一,如果超过了这个限制,则申请文件描述符失败,并且设置EMFILE错误。

RLIMIT_STACK: 设置进程最大堆栈,单位为bytes。

RLIMIT_AS: 设置进程可用内存,单位为bytes。如果超过这个限制,malloc()和mmap()将会失败,并设置ENOMEM错误。


2 lseek function

off_t lseek(int fildes, off_t offset, int whence)    移动读/写偏移量 

whence可选择的有:

SEEK_SET: 文件偏移量设置为 offset

SEEK_CUR: 文件偏移量设置为 当前偏移量 + offset

SEEK_END: 文件偏移量设置为 文件大小 + offset

获取当前偏移量的方法:

offset value = lseek(fd, 0, SEEK_CUR);

当操作的文件为 pipe, FIFO, socket时,返回-1,并设置错误为ESPIPE。

其它错误可以man 3 lseek查阅

程序用例:test2.1.cc

#include <stdio.h>
#include <unistd.h>

int main(int argc, char** argv)
{
     if(lseek(STDIN_FILENO, 0, SEEK_CUR) == -1)
          printf("Seek Failed\n");
     else
          printf("Seek OK\n");

     return 0;
}

g++ -o test2.1 test2.1.cc

./test2.1
输出:Seek Failed。原因:参数1 fildes必须是已经打开的文件描述符.

./test2.1 < /etc/passwd
输出:Seek OK




3 File Sharing -- close-on-exec

当使用fork创建子线程后,子线程获得父进程的数据空间,堆和栈的副本,也包含文件描述符,共享共同的打开文件标记,当前的偏移量等。

当在子进程中调用exec执行另一个程序时,替换了当前进程的正文,数据,堆和栈,即原先的子进程中的文件描述符丢失了(并未关闭),无法再关闭这些在子进程中不再使用到的文件描述符。而文件描述符是系统珍贵资源,数量有限。

一种办法是在执行exec之前先把这些文件描述符关闭,但在复杂的系统中,这是一件比较麻烦的事情。

另一种办法是打开文件的时候就指定好,当子进程执行exec的时候,这个文件关闭。即所谓的close-on-exec。

// 通过fcntl实现
int flags = fcntl(fd, F_GETFD);
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);

// 在创建或打开文件的时候指定
int fd = open("text.log", O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC);

具体查看man 2 open或者man 2 creat



4 Atomic Operations -- O_APPEND

有这样一个例子:

程序A和程序B对同一个文件进行写操作。
程序A先写入1500字节,程序B打开,调用lseek,得到文件末尾为1500, 写入100字节。
程序A执行,此时,程序A的file table entry记录文件末尾为1500,写入100字节。此时,覆盖了程序B写入的内容。

解决方案:

// 每次write的时候,都调用lseek,获取文件末尾偏移量。

// 在创建或者打开的时候设置参数O_APPEND, 设置此标记后,每次调用write,文件偏移量都会更新到文件末尾。



5 Atomic Operations -- pthread, pwrite

对一个文件指定位置进行写入或者读取,有两个步骤:

-1: 调用lseek,设置偏移量
-2: 调用read或者write操作。

两步操作在过程中可能被打断,得到的不是需要的结果。

而pthread/pwrite可以解决这个问题:

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); 

使用pthread/pwrite并不会改变当前文件偏移量。

当打开文件时指定了参数O_APPEND时,pwrite总是添加到文件末尾,而不会按照参数offset指定位置。 


6 dup, dup2, dup3

int dup(int oldfd);
int dup2(int oldfd, int newfd);
int dup3(int oldfd, int newfd, int flags);

这些系统调用将会创建一个文件描述符的副本。

dup将返回一个未使用的最小的文件描述符

dup2将返回一个指定的文件描述符。如果oldfd指定了文件描述标记(close-on-exec),newfd并不会拥有。
需要重新使用fcntl指定。

如果newfd已经存在,则会先被关闭。
如果oldfd和newfd数值相同,且oldfd是有效的文件描述符,则dup2不做任何事情,返回newfd。
如果oldfd和newfd数值相同,且oldfd是无效的文件描述符,则调用失败, 不会调用newfd关闭的步骤。

dup3效果与dup2相同,但可以通过指定flags为O_CLOEXEC,使得newfd具有close-on-exec功能。

如果oldfd和newfd数值相同,则调用失败,并设置错误为INVAL。


7 fcntl function

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

可以改变一个已经打开的文件的属性 

其中, cmd 可选择的有:

F_DUPFD: 返回一个大于等于参数3且最小未使用的文件描述符,与fd共享一个文件表项,如果fd有文件描述符标志(目前只有一个,FD_CLOEXEC),则此标志会被清除。可以查看dup2相关。

F_DUPFD_CLOEXEC: (since Linux 2.6.24) 效果等同于F_DUPFD,但会给返回的文件描述符添加close-on-exce标志。

F_GETFD: 返回fd的文件描述符标志。目前仅有一个标志:FD_CLOEXEC

F_SETFD: 将参数3设置为fd的文件描述符标志。

F_GETFL: 返回fd的文件状态标志,即open时候的flags标记。
               
O_RDONLY, O_WDONLY, O_RDWR, O_EXEC, O_SEARCH, 
O_APPEND, O_NONBLOCK, O_SYNC, O_DSYNC, O_RSYNC, O_FSYNC, O_ASYNC

F_SETFL: 设置fd的文件状态标志,可设置的值有(Linux下, 本机为CentOS7.0, Mac和FreeBSD有不同的选项):

O_APPEND, 每次write的时候都将添加到文件的末尾,效果等同于open的时候添加O_APPEND标记。

O_NONBLOCK, 非阻塞IO,如果read没有数据可读,或者write操作阻塞,则返回-1并且设置错误为EAGAIN。
           
O_ASYNC, 当IO可用时,允许发送SIGIO信号到进程组。

O_DIRECT, 直接进行文件IO,系统尽量不进行缓存。具体可参考以下链接:
                                        
               
O_NOATIME, 读文件不改变最后访问时间。

另外还有F_GETOWN, F_SETOWN, F_GETOWN_EX等等,具体查看fcntl(2)


8 ioctl function

ioctl 是设备驱动程序中对设备的IO通道进行管理的函数。
不同的设备驱动都会定义自己的ioctl指令。
后边讲到套接字的时候再具体详述。

再详细点的讲述可以看这里:




参考:



《unix环境高级编程》 读书笔记 (1)

标签:des   style   blog   http   os   io   使用   ar   for   

原文地址:http://blog.csdn.net/alex_my/article/details/39079053

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!