- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
在阅读 APUE(第 3 版)一书时,我遇到了 open 系统调用及其让用户打开文件进行 write
原子操作的能力,具有 O_APPEND
模式含义也就是说,多个进程可以写入文件描述符,内核确保多个进程写入单个文件的数据不会重叠,并且所有行都完好无损。
在使用 C/C++ 程序对开放式系统调用进行成功实验后,我能够对其进行验证,并且它的工作原理与书中描述的一样。我能够启动写入单个文件的多个进程,并且所有行都可以考虑到它们的进程 PID。
我希望通过 perl sysopen
观察到相同的行为,因为我有一些工作可以从这种行为中获益。尝试了一下,但实际上没有用。当我分析输出文件时,我能够看到竞争条件的迹象(可能),因为有很多次交错的行。
问题:perl sysopen
调用和linux的open系统调用不一样吗?是否可以实现这种多进程对单个文件的原子写操作?
编辑:添加 C 代码和用于测试的 perl 代码。
C/C++代码
int main(void)
{
if ((fd = open("outfile.txt",O_WRONLY|O_CREAT|O_APPEND)) == -1) {
printf ("failed to create outfile! exiting!\n");
return -1;
}
for (int counter{1};counter<=MAXLINES;counter++)
{ /* write string 'line' for MAXLINES no. of times */
std::string line = std::to_string(ACE_OS::getpid())
+ " This is a sample data line ";
line += std::to_string(counter) + " \n";
if ((n = write(fd,line.c_str(),strlen(line.c_str()))) == -1) {
printf("Failed to write to outfile!\n";
}
}
return 0;
}
Perl 代码
#!/usr/bin/perl
use Fcntl;
use strict;
use warnings;
my $maxlines = 100000;
sysopen (FH, "testfile", O_CREAT|O_WRONLY|O_APPEND) or die "failed sysopen\n";
while ($maxlines != 0) {
print FH "($$) This is sample data line no. $maxlines\n";
$maxlines--;
}
close (FH);
__END__
更新(初步故障排除后):
感谢以下答案中提供的信息,我能够让它正常工作。虽然我遇到了一些缺失行的问题,这是由于我使用 O_TRUNC
打开每个进程的文件,我不应该这样做,但最初错过了它。经过仔分割析 - 我发现了问题并进行了更正。一如既往 - Linux 永远不会让你失望:)。
这是我用来启动进程的 bash 脚本:
#!/bin/bash
# basically we spawn "$1" instances of the same
# executable which should append to the same output file.
max=$1
[[ -z $max ]] && max=6
echo "creating $max processes for appending into same file"
# this is our output file collecting all
# the lines from all the processes.
# we truncate it before we start
>testfile
for i in $(seq 1 $max)
do
echo $i && ./perl_read_write_with_syscalls.pl 2>>_err &
done
# end.
从输出文件验证:
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ ls -lrth testfile
-rw-rw-r--. 1 compuser compuser 252M Jan 31 22:52 testfile
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ wc -l testfile
6000000 testfile
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$ cat testfile |cut -f1 -d" "|sort|uniq -c
1000000 (PID: 21118)
1000000 (PID: 21123)
1000000 (PID: 21124)
1000000 (PID: 21125)
1000000 (PID: 21126)
1000000 (PID: 21127)
[compuser@lenovoe470:07-multiple-processes-append-to-a-single-file]$
观察:
令我惊讶的是,系统上根本没有等待平均负载。我没想到。我相信内核一定已经以某种方式解决了这个问题,但不知道它是如何工作的。我有兴趣了解更多。
这可能有哪些应用?
我做了很多文件到文件的协调工作,我们(在工作中)总是需要解析巨大的数据文件(例如每个 30gb - 50gb)。有了这个工作 - 我现在可以进行并行操作,而不是我以前的方法,包括:散列文件 1,然后散列文件 2,然后比较来自 2 个文件的键值对。现在我可以并行执行散列部分并进一步缩短所需时间。
谢谢
最佳答案
open
或 sysopen
都没有关系;关键是使用 syswrite
和 sysread
而不是 print
/printf
/say
/etc 和 readline
/read
/eof
/etc.
syswrite
映射到单个 write(2)
调用,而 print
/printf
/ say
/etc 会导致多次调用 write(2)
(即使启用了自动刷新)。[1]
sysread
映射到单个 read(2)
调用,而 readline
/read
/ eof
/etc 会导致多次调用 read(2)
。
因此,通过使用 syswrite
和 sysread
,如果您在POSIX系统。
print
/printf
/say
/etc,并且将您的写入限制为小于(显式)之间的缓冲区大小或自动)刷新,您将收到一个 write(2)
调用。缓冲区大小在旧版本的 Perl 中为 4 KiB,在新版本的 Perl 中默认为 8 KiB。 (大小在构建 perl
时决定。)关于linux - perl sysopen 可以打开文件进行原子写入吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54463525/
有没有办法用连词创建原子 if ?也就是说,我可以以某种方式在 C 中自动测试 if(A && B) 吗?如果它在第一个连接处短路,那么没问题,但如果没有短路,则在检查 B 时,A 可能已更改。有什么
我有很多 fork 的过程。子进程做很多事情和另一个系统调用。 当任何子进程从系统调用中获取错误时,它会将错误描述打印到 stderr 并将 SIGUSR1 发送到组长(主要父进程)。 SIGUSR1
阅读 boost::atomic 上的文档和 std::atomic 让我感到困惑的是 atomic 是否接口(interface)应该支持非平凡类型? 也就是说,给定一个只能通过将读/写包含在一个完
我有一个命令,可以将叠加图像放在视频上。 之后,我调整输出大小以适合某些尺寸。 通常一切正常,但有时且仅在某台台式计算机上,当第二次精化开始时,命令返回错误:moov atom not found 让
我最近发现当 LANG 设置为 C.utf8 时,X11 原子 WM_NAME 未在 Swing JFrame 中设置。但为 LANG 的其他值设置。这发生在带有 OpenJDK 11.0.9 的 L
我目前正在使用blackmagic的prorecorder录制视频。我使用 ffmpeg 将视频即时转码为 mp4 视频容器。持续时间未知,因为我正在对 prorecorder 输出到命名管道的 .t
这里真的有人使用 atom 来处理 git 提交消息吗?我想但我遇到了这个问题并且一直坚持使用 git commit -m '....' 。当我尝试使用 atom 时,它会打开 atom,我几乎立即从
考虑: void foo() { std::vector> foo(10); ... } foo 的内容现在有效吗?或者我是否需要显式循环并初始化它们?我检查过 Godbolt,看起来不错,但
在official FAQ我阅读的 Memcached: “发送到 memcached 的所有单独命令都是绝对原子的。” 然而,当涉及到 get_multi 和 set_multi 时,我仍然不清楚。
在测试程序的可扩展性时,我遇到了必须将 memcpy 操作设置为原子操作的情况。我必须将 64 字节的数据从一个位置复制到另一个位置。 我遇到了一种解决方案,即使用旋转变量: struct recor
我对 C++ 原子变量感到困惑。如果我有一个原子 x,我想在一个线程中递增并在另一个线程中读取,我可以执行++x 还是必须执行 x.atomic_fetch_add(1)。在读者线程中,我可以做类似
跟进自 Multiple assignment in one line ,我很想知道这对原子数据类型是如何工作的,特别是 bool 类型的例子。 给定: class foo { std::at
我想创建一个版本控制系统,并且对版本号为 1 的新条目的查询如下所示: ID 和修订号组合起来就是主键。 insert into contentfile (id, name, revision, ac
我在 iOS 项目中有下一个独立的测试片段: /// ... std::atomic_bool ab; ab.store(true); bool expected = false; while (!a
我了解如何使用条件变量(此构造的名称很糟糕,IMO,因为 cv 对象既不是变量也不表示条件)。所以我有一对线程,canonically使用 Boost.Thread 设置为: bool awake =
因此,对于最终项目,我尝试制作一款包含三种不同 meteor 的游戏;铜牌、银牌和金牌。虽然青铜阵列在Setup()中工作正常,但银色和金色 meteor 由于某种未知原因而高速移动。 functio
第一个问题,为什么不在 atomic_compare_exchange_weak 操作的参数中应用后缀求值 (++)?运算前后a的值相同。然而,当在 printf() 中使用时,正如预期的那样,该值会
我正在尝试使用 OpenMP 对已经矢量化的代码进行内部函数并行化,但问题是我使用一个 XMM 寄存器作为外部“变量”,我会在每个循环中递增。现在我正在使用 shared 子句 __m128d xmm
clojure“atom”的文档指出 - "Changes to atoms are always free of race conditions." 但是,竞争条件不仅根据更改定义,而且在不同线程中
我一直在研究原子引用计数的实现。 库之间的大多数操作都非常一致,但我在“减少引用计数”操作中发现了惊人的多样性。 (请注意,通常情况下,shared 和 weak decref 之间的唯一区别是调用了
我是一名优秀的程序员,十分优秀!