# Ch14 Advanced I/O >###### tags: `APUE` >致謝 >W. Richard Stevens : >*Advanced Programming in the UNIX Environment III* >XutongLi >https://github.com/XutongLi/Learning-Notes >大木實驗室 >https://www.bilibili.com/s/video/BV1NJ411x7Mq ## blocking & nonblocking I/O ### blocking * (Read/Write) that can block the caller forever if data (isn’t present/can't be accepted) with certain file types such as *pipes*, *terminal devices*, and *network devices*. * open that block until some event occur * mandatory lock ### nonblocking Nonblocking I/O lets us issue an I/O operation, such as an open, read, or write, and not have it block forever. If the operation cannot be completed, the call returns immediately with an error noting that the operation would have blocked. 2 ways to specify nonblocking I/O for a given descriptor. * If we call open to get the descriptor, specify the O_NONBLOCK flag. * For a descriptor already open, call fcntl to turn on O_NONBLOCK file status flag. **blocking code** ```c= #include <stdio.h> #include <string.h> #include <unistd.h> int main(int argc, char** argv){ char buffer[100]; bzero(buffer,100); int ret = read(STDIN_FILENO,buffer,100); //program will block here write(STDOUT_FILENO,buffer,100); return 0; } ``` **nonblocking code** ```c= #include <stdio.h> #include <string.h> #include <unistd.h> #include <assert.h> #include <fcntl.h> int main(int argc, char** argv){ char buffer[100]; bzero(buffer,100); int flag = fcntl(STDIN_FILENO,F_GETFL); int ret = fcntl(STDIN_FILENO, F_SETFL, flag|O_NONBLOCK); assert(ret != -1); while(1){ int n_byte = read(STDIN_FILENO, buffer, 100); if(n_byte < 0){ write(STDOUT_FILENO, "-", 1); sleep(1); } else{ fprintf(stdout, "Input:%s\n",buffer); } } return 0; } ``` **ideas** The nonblocking program issues lots of write calls of no use. This type of loop, called polling, is a waste of CPU time on a multiuser system. Sometimes, we can avoid using nonblocking I/O by coding our program to use multiple threads. ## Record Locking What happens when two people edit the same file at the same time? *Record locking* is the term normally used to describe the ability of a process to prevent other processes from modifying a region of a file while the first process is reading or modifying that portion of the file. ```c = #include <fcntl.h> int fcntl(int fd, int cmd, ... /* struct flock *flockptr */ ); //Returns: depends on cmd if OK (see following), −1 on error ``` For record locking, cmd is *F_GETLK, F_SETLK, or F_SETLKW*. The third argument is a pointer to an flock structure. ```c= struct flock { short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */ short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */ off_t l_start; /* offset in bytes, relative to l_whence */ off_t l_len; /* length, in bytes; 0 means lock to EOF */ pid_t l_pid; /* returned with F_GETLK */ }; ``` **Compatibility** The rule applies to lock requests made from different processes, not to multiple lock requests made by a single process. If a process has an existing lock on a range of a file, a subsequent attempt to place a lock on the same range will replace the existing lock with the new one. | Column 1 | read lock | write lock | | -------- | --------- | ---------- | | no locks | OK | OK | | one or more read locks | OK | Denied | | one write lock | Denied | Denied | **Place a write lock on an entire file** ```c = #include <unistd.h> #include <fcntl.h> int lockfile(int fd) { struct flock fl; fl.l_type = F_WRLCK; fl.l_start = 0; fl.l_whence = SEEK_SET; fl.l_len = 0; return(fcntl(fd, F_SETLK, &fl)); } ```