Linux编程实践Day5

学习stty

设备文件

设备文件名使用ls /dev命令在/dev中查看

终端就像文件

设备文件与磁盘文件的区别

  1. 常用的磁盘文件由字节组成,磁盘文件中的字节数就是文件的大小。而对于设备文件而言,其i节点指向的是对应的设备驱动程序指针,当应用程序对设备文件进行读写操作时,内核会根据i节点,调用相应的内核子程序来执行实际的设备操作。
  2. 进程到磁盘的字节会先被缓冲,然后才从内核的缓冲区发送出去,而进程需要尽快把到设备文件的数据传送出去。

磁盘文件属性

通过fcntl修改缓冲属性

1
2
3
4
5
6
7
#include <fcntl.h>
int s;
s = fcntl(fs, F_GETFL);
s |= O_SYNC;
if(fcntl(fd, F_SETFL, s) == -1){
perror("setting SYNC error");
}

参数F_GETFL用于得到当前的位集,O_SYNC位用于告诉内核对write的调用只能在数据写入实际的硬件是才能返回,而不是数据复制到缓冲区就返回,这样可以保证数据一定被写入

自动添加append模式

当文件描述符的O_APPEND位被开启后,每个对write的调用将自动调用lseek将内容添加到文件的末尾,并且可以保证多进程同时写入时,不会出现死锁或错误写入。

设备文件属性

使用stty命令改变驱动属性

1
2
3
4
stty erase X # make 'X' the erase key
stty -echo # type invisibly
stty echo # type visibly
stty erase @ echo # mutiple cmds

通过程序改变驱动属性

  • 从驱动程序获得属性
  • 修改所要修改的属性
  • 将修改过的属性送回驱动程序

termios structure

1
2
3
4
5
tcflag_t c_iflag;      /* input modes */
tcflag_t c_oflag; /* output modes */
tcflag_t c_cflag; /* control modes */
tcflag_t c_lflag; /* local modes */
cc_t c_cc[NCCS]; /* special characters */
1
2
3
4
5
#include <termios.h>
struct termios attribs;
tcgetattr(fd, &settings);
settings.c_lflag |= ECHO;
tcsetattr(fd, TCSANOW, &settings);

除了TCSANOW以外,还有

tips

homework

link是可以用来给文件上锁的,但现如今已被淘汰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* 测试两个进程同时创建硬链接,可以得知系统调用link可以起到给文件上锁的作用 */
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>

int LockPasswd(){
int rv = 0;
if(link("./test.txt", "./test_link.txt") == -1)
rv = errno;
return rv;
}

int main() {
// 创建子进程
pid_t pid = fork();

if (pid < 0) {
perror("无法创建子进程");
return 1;
} else if (pid == 0) {
// 子进程执行代码
int result = LockPasswd();
printf("子进程执行结果:%d\n", result);
} else {
// 父进程执行代码
int result = LockPasswd();
printf("父进程执行结果:%d\n", result);
}

return 0;
}

结果如图

使用O_SYNC测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>

#define BUFFER_SIZE 1024

const char* input_file = "./sync_exp/input";
const char* output_dir = "./sync_exp/output";

void split_file() {
int in_fd = open(input_file, O_RDONLY);
if (in_fd == -1) {
perror("Failed to open input file");
return;
}

unsigned char buffer[BUFFER_SIZE];
int cnt = 0;

while((read(in_fd, buffer, BUFFER_SIZE)) != 0){
char output_file[100];
sprintf(output_file, "./sync_exp/output/%d", cnt++);
int out_fd = open(output_file, O_WRONLY | O_CREAT | 0777);
if (out_fd == -1) {
perror("Failed to create output file");
return;
}

write(out_fd, buffer, BUFFER_SIZE);
close(out_fd);
}

close(in_fd);
}

int main() {
clock_t start = clock();
split_file();
clock_t end = clock();
double time_taken = (double)(end - start) / CLOCKS_PER_SEC;
printf("time cost: %f\n", time_taken);
return 0;
}

开启缓冲的结果

关闭缓冲的结果

结论
在1G的input文件轰炸下,关闭缓冲仍然不会太明显地影响速度,可能这就和linux内核实现有关了


Linux编程实践Day5
http://bugeater.space/2023/10/07/Linux编程实践Day5/
Author
BugEater
Posted on
October 7, 2023
Licensed under