Linux system programming: atomic operation experiment in the IO read/write process, linuxio
The so-called atomic operation means that the kernel ensures that all steps (Operations) in a system call are executed as independent operations at one time without being interrupted by other processes or threads.
For example, when you and your girlfriend OOXX have a sudden call, they will inevitably interrupt your climax. The best way is, when you do this, by shutting down the communication device, we can ensure that this operation is completed successfully. This is an atomic operation.
In multi-process I/O processes, operations that are not atomic may cause data confusion and mutual coverage. This phenomenon is also called competition.
The so-called competition state means that the results of two processes (or threads) operating on shared resources depend on an unexpected order, because the cpu execution time obtained by the process is uncertain.
1. Create a file exclusively.
The following code uses the open and O_CREAT signs to demonstrate how to create an exclusive file. What is exclusive file creation? That is, the process always thinks that the file is opened by him or created by him.
1/* ============================================== =========================================== 2 * Copyright (C) 2018. all rights reserved. 3*4 * file name: bad_exclusive_open.c 5 * Creator: ghostwu (Wu Hua) 6 * creation Date: July 7 * description: 8*9 ============================================ ================== */10 11 # include <stdio. h> 12 # include <sys/types. h> 13 # include <sys/stat. h> 14 # include <fcntl. h> 15 # include <stdlib. h> 16 # include <String. h> 17 # include <sys/types. h> 18 # include <unistd. h> 19 # include <errno. h> 20 21 22 int main (int argc, char * argv []) 23 {24 if (argc <2 | strcmp (argv [1], "-- help ") = 0) {25 printf ("usage: % s filename \ n", argv [0]); 26 exit (-1 ); 27} 28 29 printf ("pid = % d, % s file does not exist \ n", getpid (), argv [1]); 30 31 int fd =-1; 32 33 fd = open (argv [1], O_WRONLY); 34 if (fd <0) {35 sleep (5); 36 printf ("pid = % d, end Bundle sleep \ n ", getpid (); 37 // other error causes, resulting in file opening failure 38 if (errno! = ENOENT) {39 perror ("open"); 40 exit (-1 ); 41} else {42 // file opening failed because the file does not exist 43 fd = open (argv [1], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); 44 if (fd <0) {45 printf ("file % s creation failed \ n", argv [1]); 46 exit (-1); 47} 48 printf ("file % s, created and opened successfully: fd = % d \ n ", argv [1], fd); 49 printf (" process id = % d \ n ", getpid ()); 50 close (fd); 51} 52} else {53 printf ("file % s, opened successfully: fd = % d \ n", argv [1], fd ); 54 printf ("process id = % d \ n", getpid (); 55 close (fd); 56} 57 58 59 return 0; 60}View Code
Assume that we want to create an existing test.txt file.
For demonstration convenience, when the program first determines that the file does not exist, let the process suspend (sleep 5) to hand over the cpu execution time. At this time, we can test the following two methods:
1. Create the test.txt file for another account (for example, rootaccount)
2. Start another process on another terminal.
Method 1: Create a test.txt with the shellscript and grant the rw permission to other groups.
Createfile. sh
1 #! /Bin/bash2 # create a file and change the permission to test 3 4 touch test.txt 5 sudo chmod a + rw test.txt
Experiment results: the process on the left still thinks this file was created and opened by him!
Method 2: Test another process on another terminal
Test.txt is created and opened by themselves.
2. How can I create a file exclusively?
It is very simple, just add a flag O_EXCL, combined with O_CREAT
fd = open( argv[1], O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR );
Test again according to the above two methods. The result is:
If another process creates a file during sleep, the process reports an error.
3. seek and write are combined to generate mutual coverage1/* ============================================== =========================================== 2 * Copyright (C) 2018. all rights reserved. 3*4 * file name: seek_file.c 5 * Creator: ghostwu (Wu Hua) 6 * creation Date: July 6, January 11, 2018 7 * description: 8*9 ============================================ ================== */10 11 # include <stdio. h> 12 # include <stdlib. h> 13 # include <string. h> 14 # include <sys/types. h> 15 # include <sys/stat. h> 16 # include <fcntl. h> 17 # include <sys/types. h> 18 # include <unistd. h> 19 20 # ifndef BUFSIZE21 # define BUFSIZE 5022 # endif23 24 25 int main (int argc, char * argv []) 26 {27 if (argc <3 | strcmp (argv [1], "-- help") = 0) {28 printf ("usage: % s filename w <string> \ n ", argv [1]); 29 exit (-1); 30} 31 32 if (argv [2] [0]! = 'W') {33 printf ("must start with w \ n"); 34 exit (-1); 35} 36 37 int fd =-1; 38 fd = open (argv [1], O_RDWR); 39 40 if (fd <0) {41 printf ("file % s opening failed \ n ", argv [1]); 42 exit (-1); 43} 44 45 if (-1 = lseek (fd, 0, SEEK_END )) {46 printf ("failed to move pointer to tail \ n"); 47 exit (-1); 48} 49 50 sleep (5); 51 52 char buf [BUFSIZE]; 53 ssize_t nwrite; 54 55 strcpy (buf, & argv [2] [1]); 56 57 nwrite = write (fd, buf, strlen (buf )); 58 if (-1 = nwrite) {59 printf ("file write failed \ n"); 60 exit (-1); 61} 62 printf ("pid = % d, % ld bytes \ n ", getpid (), argv [1], nwrite); 63 64 return 0; 65} are written to the file % s}View Code
If the first process is executed between seek and write, the cpu is handed over, and the second process that executes the same code is interrupted, the two processes move the pointer to the same position before writing data, if a process is completed first, the latter process will overwrite the data written by the previous process.
Test results:
End after the second process: 123 written by the first process is overwritten by 4567 of the second process, resulting in 4567
End after the first process: 4567 written to the first process is overwritten by 123 of the second process, and result 1237 is generated.
How to avoid data coverage? When opening the file, add the O_APPEND flag
fd = open( argv[1], O_RDWR | O_APPEND );
Summary:
1) understand atomic operations
2) understand the significance of the combination of O_CREAT and O_EXCL
3) understand the O_APPEND flag
4) understand the competition status