原子操作指的是不可被中断或分割的基本操作,它在执行过程中要么完全执行成功,要么完全不执行,不会被其他并发操作所干扰。
原子操作是确保对共享资源进行并发访问时线程安全的关键,通常由硬件或操作系统提供支持,并且能够保证在多线程或多进程环境下的安全性。
常见的原子操作包括原子增加、原子减少、原子交换等。这些操作能够保证在并发执行时不会发生竞争冒险或数据竞争(Data Race),从而确保数据的一致性和完整性。
在并发编程中,原子操作通常用于保护共享资源的访问和修改,以防止多个线程同时访问或修改同一共享资源而导致的竞争冒险。使用原子操作能够简化并发编程的同步机制,并且能够提高程序的性能和效率。
例如:有两个应用程序 A和B,都对同一个文件进行写操作,进程A先写入,那么后写入的进程B就会把A写入的数据覆盖掉。
解决办法就是将“先定位到文件末尾,然后写”这两个步骤组成一个原子操作,由此引入pread和pwrite函数。
1.pread
用于带偏移量的从文件中读取数据,无法中断其定位和读操作,不更新文件表中当前的位置偏移量。
1)头文件
#include <unistd.h>
2)函数原型
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
3)参数
fd:表示要操作文件的文件描述符。
buf:表示读出数据存放的位置(缓冲区地址)。
count:表示读出的字节数。
offset:表示当前需要进行读的位置偏移量。
4)返回值
若读取成功则返回实际读到的字节数,若已到文件结尾则返回0,若出错则返回-1。
5)示例:(带偏移量的从文件中读取特定数据,查看读取后的文件偏移量)
| #include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdio.h> int main(){ char bufwrite[30] = "HELLO WORLD!!!n"; char bufread[30]; int fd, lk; fd = open("./test", O_RDWR | O_CREAT | O_TRUNC, 0666); //打开文件test if (fd < 0) { printf("error: test openn"); return -1; } if ( write(fd, bufwrite, strlen(bufwrite)) < 0 ) { //向文件test写入特定内容 printf("error: test writen"); close(fd); return -1; } if (pread(fd, bufread, 3, 2) < 0) { //读取2字节后的3字节内容 printf("error: test preadn"); close(fd); return -1; } lk = lseek(fd, 0,SEEK_CUR); //获取当前偏移量位置 if (lk < 0) { printf("error: test lseekn"); close(fd); return -1; } printf("pread fd:%s", bufread); printf("lseek fd:%dn", lk); close(fd); return 0; } |
6)编译运行并查看测试结果
| pread fd:LLO //读取到2字节后的3字节内容
lseek fd:15 //第一次写入后的偏移量,而不是pread读取的位置 |
2.pwrite
用于带偏移量的向文件中写入数据,无法中断其定位和写操作,不更新文件表中当前的位置偏移量。
1)头文件
#include <unistd.h>
2)函数原型
ssize_t pwrite(intfd, const void *buf, size_tcount, off_toffset);
3)参数
fd:表示要操作文件的文件描述符。
buf:表示要写的数据(缓冲区地址)。
count:表示写入的字节数。
offset:表示当前需要进行写的位置偏移量。
4)返回值
成功,返回写入到文件中的字节数;失败,返回-1。
5)示例:(带偏移量的向文件写入特定数据,查看写入后的文件偏移量)
| #include <sys/types.h>
#include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main() { char bufwrite[30] = "HELLO WORLD!!!n"; char bufWrite[30] = "pwrite test!n"; char bufread[30]; int fd, lk; fd = open("./test", O_RDWR | O_CREAT | O_TRUNC, 0666); if (fd < 0) { printf("error: test openn"); return -1; } if ( write(fd, bufwrite, strlen(bufwrite)) < 0 ) { //向文件test写入特定内容 printf("error: test writen"); close(fd); return -1; } if (pwrite(fd, bufWrite, strlen(bufWrite), 15) < 0) { //带偏移量向文件test写入特定内容 printf("error: test preadn"); close(fd); return -1; } if (pread(fd, bufread, 30, 5) < 0) { //带偏移量读取test特定内容 printf("error: test preadn"); close(fd); return -1; } lk = lseek(fd, 0, SEEK_CUR); if(lk < 0) { printf("error: test lseekn"); close(fd); return -1; } printf("pread fd: %s", buf); printf("lseek fd: %dn", lk); close(fd); return 0; } |
6)编译运行并查看测试结果
| pread fd: WORLD!!!
pwrite test! lseek fd: 15 |
221