首页 > 解决方案 > Perl 线程——它们可以被唯一命名吗?(Linux)

问题描述

perlvar参考这个:

在多线程脚本中,Perl 协调线程,以便任何线程都可以修改其 $0 的副本,并且更改对 ps(1) 可见(假设操作系统在运行)。请注意,其他线程拥有的 $0 视图不会改变,因为它们有自己的副本。

我似乎没有得到这种行为。相反,$0 似乎由我的所有线程共享,并且在 ps 输出中,顶级主 perl 解释器的 cmdline 被修改为最后一个线程应用的最终值。

例如。我的目标不是让所有线程在 COMMAND 列下命名相同:

top -b -n 1 -H -p 223860

top - 17:54:56 up 73 days,  2:15,  7 users,  load average: 0.23, 0.70, 0.92
Threads:  22 total,   0 running,  22 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 32358832 total, 26418060 free,  1090028 used,  4850744 buff/cache
KiB Swap: 16777212 total, 16149116 free,   628096 used. 30804716 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
223860 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:45.75 tool_reader.
223863 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:03.88 tool_reader.
223864 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:04.67 tool_reader.
223865 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:00.00 tool_reader.
223867 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:34.62 tool_reader.
223868 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:03.85 tool_reader.
223869 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:04.41 tool_reader.
223870 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:00.00 tool_reader.
223872 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:40.14 tool_reader.


像这样在命令列下有一些更有用的东西,并且主线程保持不变。

                                                                             |
                                                                             |
                                                                             |
                                                                             v
top -b -n 1 -H -p 223860

top - 17:54:56 up 73 days,  2:15,  7 users,  load average: 0.23, 0.70, 0.92
Threads:  22 total,   0 running,  22 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 32358832 total, 26418060 free,  1090028 used,  4850744 buff/cache
KiB Swap: 16777212 total, 16149116 free,   628096 used. 30804716 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
223860 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:45.75 tool_reader.
223863 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:03.88 syncer
223864 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:04.67 partition1
223865 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:00.00 partition2
223867 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:34.62 partition3
223868 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:03.85 input_merger1
223869 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:04.41 input_merger2
223870 app_sy+  20   0 3833640 166216   2500 S  0.0  0.5   0:00.00 input_merger3


有谁知道如何做到这一点?我现在使用的是相当旧的 perl,版本 5.16.3,以防这是一个错误?

标签: linuxmultithreadingperl

解决方案


2020 年 10 月 21 日更新: 我刚刚发现了一种更好的方法来实现这一点 - 实际的 linux 系统调用。https://man7.org/linux/man-pages/man2/prctl.2.html

Troels Liebe Bentsen 提供了一个可以巧妙处理此问题的模块。 https://metacpan.org/pod/Sys::Prctl

比摆弄 $0 无缝多了!!!

原始帖子内容在下面继续......

ps -T -p 126193
   PID   SPID TTY          TIME CMD
126193 126193 pts/11   00:00:00 test2.pl
126193 126194 pts/11   00:00:00 __thr1      #<--- now unique
126193 126195 pts/11   00:00:00 __thr2      #<--- now unique
top -H -p 126193

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
126193 xxxxxxx+  20   0  305948   7972   2244 S  0.0  0.0   0:00.01 test2.pl
126194 xxxxxxx+  20   0  305948   7972   2244 S  0.0  0.0   0:00.00 __thr1
126195 xxxxxxx+  20   0  305948   7972   2244 S  0.0  0.0   0:00.00 __thr2

##################

感谢@ikegami,我找到了一个可行的解决方案。

为了使子线程保持活动状态,需要进行一些小的更改,并且还需要阻止主线程重新加入它们。(根据它的行为,我假设如果子线程到达子线程的末尾它们被生成,它们被完全终止,Linux 清理它们——即使主线程还没有调用join它们。

对于将来阅读此页面的其他人,我很想知道为什么 pstree、ps 和 top 都显示不同的结果。

无论如何,将这些信息和比较留在这里,以防对其他人有帮助。

最终结果:

  • 使用pscommand ,似乎无法获得修改后的线程名称。它只显示最后一个触及 $0 的线程将其设置为的字符串
  • 同样,使用 pstreepstree -p -a -l 144741也仅将主线程显示为每个子线程的名称,而不会显示有关线程所做更改的任何内容
  • 但是,非常幸运的是,使用了顶级作品!!!!top -H -b -p 180547,它清楚地显示了主线程和所有子线程,它们使用 $0 设置的名称

来自ps的例子:

app_sy+ 180547 131203 180547  0    3 18:08 pts/1    00:00:00 thr2
app_sy+ 180547 131203 180548  0    3 18:08 pts/1    00:00:00 thr2
app_sy+ 180547 131203 180549  0    3 18:08 pts/1    00:00:00 thr2

使用 pstree 的示例:

test.pl,180547
  |-{test.pl},180548
  `-{test.pl},180549

获胜者 usingtop -n 1 -H -b -p 180547显示每个线程成功应用到 $0 的不同名称!!!!!!

top - 18:00:08 up 69 days,  8:53,  3 users,  load average: 4.10, 3.95, 4.05
Threads:   3 total,   0 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  7.7 us, 33.5 sy,  0.0 ni, 58.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 13144056+total,  1351640 free, 45880316 used, 84208608 buff/cache
KiB Swap: 16777212 total, 16777212 free,        0 used. 78196224 avail Mem

   PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
180547 app_+     20   0  299572   7152   2144 S  0.0  0.0   0:00.00 test.pl
180548 app_+     20   0  299572   7152   2144 S  0.0  0.0   0:00.02 thr1
180549 app_+     20   0  299572   7152   2144 S  0.0  0.0   0:00.01 thr2

在此处添加 Ikegami 代码的修改版本以供查看此页面的其他人将来参考,另存为 test.pl :

#!/usr/bin/perl

use strict;
use warnings;
use feature qw( say );
use threads;
use threads::shared;

my $phase :shared = 0;
my $main_pid = $$;
sub advance {
   lock $phase;
   ++$phase;
   cond_signal($phase);
}

sub wait_for {
   lock $phase;
   cond_wait($phase) while $phase != $_[0];
}

sub advance_and_wait_for {
   lock $phase;
   ++$phase;
   cond_signal($phase);
   cond_wait($phase) while $phase != $_[0];
}

my $thr1 = async {
   my $id = 'thr1';
   wait_for(0);
   advance_and_wait_for(2);
   say "[$id] Setting \$0 to $id.";
   $0 = $id;
   say "[$id] \$0 = $0";
   print `ps -eLf|grep $main_pid` =~ s/^/[$id] /mrg;
   advance_and_wait_for(4);
   say "[$id] \$0 = $0";
   advance();
    while(1){
        sleep 1;
    }
};

my $thr2 = async {
   my $id = 'thr2';
   wait_for(1);
   advance_and_wait_for(3);
   say "[$id] \$0 = $0";
   say "[$id] Setting \$0 to $id.";
   $0 = $id;
   say "[$id] \$0 = $0";
   print `ps -eLf| grep $main_pid` =~ s/^/[$id] /mrg;
   advance();
    while(1){
        sleep 1;
    }

};
sleep 5;
print "Main thread pid is $main_pid - and \$0 is ($0)\n";

my $waitfor = <STDIN>;

$_->join for $thr1, $thr2;

推荐阅读