非阻塞I/O,记录锁,I/O多路转接(select/poll),readv和writev函数以及存储映射I/O,这些统称为高级I/O。
1.非阻塞I/O
非阻塞I/O使我们可以调用永远不会阻塞的I/O操作。例如open,read和write。如果这些操作不能完成,则立即出错返回。表示该操作如果继续执行将继续阻塞下去。
2.记录锁
fcntl记录锁
记录锁的功能是:一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区。
成功根据cmd返回。出错返回-1。
第一个参数:文件描述符
第二个参数:对于记录锁,cmd是F_GETLK,F_SETLK或F_GETLKW。
第三个参数:是一个指向结构体的指针
flock结构体说明:
所希望的锁类型:F_RDLCK(共享读锁)、F_WRLCK(独占性写锁)、F_UNLCK(解锁一个区域)。这是由l_type决定的。
要加锁或解锁区域的起始字节偏移量。这是由whence决定的。
区域的字节长度:len。
具有能阻塞当前进程的锁,其持有的ID存放在l_pid中。
注意事项:
1.加读锁时,该描述符是读打开的,加写锁时,该描述符必须是写打开。
2.兼容性规则适用于不同进程提出的锁要求,并不适用于单个进程提出的多个锁要求。如果一个进程对一个文件区已经有了一把锁,后来该进程又企图在同一文件区再加一把锁,那么新锁将替换旧锁。
锁的隐含继承和释放
a.锁与进程、文件两方面有关。这有两重含义,第一重含义:当一个进程终止时,它所建立的锁全部释放,第二重含义:任何时候关闭一个描述符时,则该进程通过这一文件描述符可以存访的文件上任何一把锁都被释放。
b.由fork产生的子进程不继承父进程所设置的的锁。
c.在执行exec后,新程序可以继承原执行程序的锁。
pipe/socketpair
pipe用来创建管道,但是单个管道只能单向通信,一端用于读,一端用于写。如果要实现进程双向通信,必须创建一对管道。而socketpair可以创建双向通信:
mysocketpair
/*************************************************************************
> File Name: mysockpair.c
> Author: ZX
> Mail: 18829897183@163.com
> Created Time: Mon 13 Mar 2017 08:15:16 AM PDT
************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<string.h>
int main()
{
int sv[2];
int ret = socketpair(AF_LOCAL, SOCK_STREAM, 0, sv);
if(ret != 0)
{
perror("socketpair");
return 1;
}
char* msg = "hello world";
int id = fork();
if(id < 0)
{
perror("fork");
return 2;
}
else if(id == 0)
{//child
close(sv[0]);
char buf[1024];
while(1)
{
memset(buf, 0, sizeof(buf));
strcpy(buf, msg);
write(sv[1], msg,sizeof(buf));
read(sv[1], buf, sizeof(buf));
sleep(1);
printf("child# %s\n",buf);
}
}
else
{//father
close(sv[1]);
char buf[1024];
while(1)
{
memset(buf, 0, sizeof(buf));
read(sv[0], buf, sizeof(buf));
printf("father# %s\n",buf);
strcpy(buf, msg);
write(sv[0], msg, sizeof(buf));
}
}
return 0;
}
Makefile
mysockpair:mysockpair.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f mysockpair
dup/dup2
对输入文件描述符重定向
mydup.c
/*************************************************************************
> File Name: mydup.c
> Author: ZX
> Mail: 18829897183@163.com
> Created Time: Sun 19 Mar 2017 06:18:49 PM PDT
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd = open("./log", O_CREAT| O_RDWR);
if(fd < 0)
{
perror("open");
return 1;
}
close(1);
int new_fd = dup(fd);
if(fd == -1)
{
perror("dup");
return 2;
}
close(fd);
char buf[1024];
int i = 0;
while(i++<10)
{
//ssize_t _s = read(new_fd, buf, sizeof(buf)-1);
//if(_s < 0)
//{
// perror("read");
// return 3;
//}
//
printf("hello world! %d\n",i);
//printf("buf: %s\n",buf);
fflush(stdout);
}
close(new_fd);
return 0;
}
mydup2.c
/*************************************************************************
> File Name: mydup2.c
> Author: ZX
> Mail: 18829897183@163.com
> Created Time: Sun 19 Mar 2017 06:41:07 PM PDT
************************************************************************/
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int fd = open("./log", O_CREAT|O_RDWR);
if(fd < 0)
{
perror("open");
return 1;
}
close(1);
int new_fd = dup2(fd, 1);
if(new_fd == -1)
{
perror("dup2");
return 2;
}
int i = 0;
while(i++<10)
{
printf("hello bit! i: %d\n",i);
fflush(stdout);
}
close(new_fd);
return 0;
}
将newfd重定向到oldfd。这里是将标准输出重定向,本来应该打印在标准输出的内容打印在文件中了。