gpt4 book ai didi

multithreading - 在 Perl 中是否有线程安全的打印方式?

转载 作者:行者123 更新时间:2023-12-04 17:35:03 26 4
gpt4 key购买 nike

我目前有一个脚本,可以启动线程以在多个目录上执行各种操作。我的脚本片段是:

#main
sub BuildInit {

my $actionStr = "";
my $compStr = "";

my @component_dirs;
my @compToBeBuilt;
foreach my $comp (@compList) {
@component_dirs = GetDirs($comp); #populates @component_dirs
}

print "Printing Action List: @actionList\n";

#---------------------------------------
#---- Setup Worker Threads ----------
for ( 1 .. NUM_WORKERS ) {
async {
while ( defined( my $job = $q->dequeue() ) ) {
worker($job);
}
};
}

#-----------------------------------
#---- Enqueue The Work ----------
for my $action (@actionList) {
my $sem = Thread::Semaphore->new(0);
$q->enqueue( [ $_, $action, $sem ] ) for @component_dirs;

$sem->down( scalar @component_dirs );
print "\n------>> Waiting for prior actions to finish up... <<------\n";
}

# Nothing more to do - notify the Queue that we're not adding anything else
$q->end();
$_->join() for threads->list();

return 0;
}

#worker
sub worker {
my ($job) = @_;
my ( $component, $action, $sem ) = @$job;
Build( $component, $action );
$sem->up();
}

#builder method
sub Build {

my ( $comp, $action ) = @_;
my $cmd = "$MAKE $MAKE_INVOCATION_PATH/$comp ";
my $retCode = -1;

given ($action) {
when ("depend") { $cmd .= "$action >nul 2>&1" } #suppress output
when ("clean") { $cmd .= $action }
when ("build") { $cmd .= 'l1' }
when ("link") { $cmd .= '' } #add nothing; default is to link
default { die "Action: $action is unknown to me." }
}

print "\n\t\t*** Performing Action: \'$cmd\' on $comp ***" if $verbose;

if ( $action eq "link" ) {

# hack around potential race conditions -- will only be an issue during linking
my $tries = 1;
until ( $retCode == 0 or $tries == 0 ) {
last if ( $retCode = system($cmd) ) == 2; #compile error; stop trying
$tries--;
}
}
else {
$retCode = system($cmd);
}
push( @retCodes, ( $retCode >> 8 ) );

#testing
if ( $retCode != 0 ) {
print "\n\t\t*** ERROR IN $comp: $@ !! ***\n";
print "\t\t*** Action: $cmd -->> Error Level: " . ( $retCode >> 8 ) . "\n";

#exit(-1);
}

return $retCode;
}
print我希望线程安全的声明是: print "\n\t\t*** Performing Action: \'$cmd\' on $comp ***" if $verbose;理想情况下,我想要这个输出,然后每个组件都有 $action对其执行,将在相关块中输出。但是,这显然现在不起作用 - 输出大部分是交错的,每个线程都吐出自己的信息。

例如。,:
ComponentAFile1.cpp
ComponentAFile2.cpp
ComponentAFile3.cpp
ComponentBFile1.cpp
ComponentCFile1.cpp
ComponentBFile2.cpp
ComponentCFile2.cpp
ComponentCFile3.cpp
... etc.

我考虑过使用反引号执行系统命令,并在一个大字符串或其他东西中捕获所有输出,然后在线程终止时将其全部输出。但是这个问题是(a)它似乎非常低效,并且(b)我需要捕获 stderr .

任何人都可以看到一种将每个线程的输出分开的方法吗?

澄清:
我想要的输出是:
ComponentAFile1.cpp
ComponentAFile2.cpp
ComponentAFile3.cpp
------------------- #some separator
ComponentBFile1.cpp
ComponentBFile2.cpp
------------------- #some separator
ComponentCFile1.cpp
ComponentCFile2.cpp
ComponentCFile3.cpp
... etc.

最佳答案

为确保您的输出不被中断,对 STDOUT 和 STDERR 的访问必须是互斥的。这意味着在线程开始打印和完成打印之间,不允许其他线程进行打印。这可以使用 Thread::Semaphore[1] 来完成。

一次捕获输出并打印出来可以减少线程持有锁的时间。如果您不这样做,您将有效地使您的系统成为单线程系统,因为每个线程在一个线程运行时尝试锁定 STDOUT 和 STDERR。

其他选项包括:

  • 为每个线程使用不同的输出文件。
  • 在每行输出前添加作业 ID,以便稍后对输出进行排序。

  • 在这两种情况下,您只需要在很短的时间内锁定它。


  • # Once
    my $mutex = Thread::Semaphore->new(); # Shared by all threads.


    # When you want to print.
    $mutex->down();
    print ...;
    STDOUT->flush();
    STDERR->flush();
    $mutex->up();

    或者
    # Once
    my $mutex = Thread::Semaphore->new(); # Shared by all threads.
    STDOUT->autoflush();
    STDERR->autoflush();


    # When you want to print.
    $mutex->down();
    print ...;
    $mutex->up();
  • 关于multithreading - 在 Perl 中是否有线程安全的打印方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23063973/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com