IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址

Posted

技术标签:

【中文标题】IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址【英文标题】:IPC::Shareable variables, "Can't use string ... as a SCALAR ref.." and memory address 【发布时间】:2012-05-19 19:57:47 【问题描述】:

请注意以下最小工作示例:

use warnings;
use strict;
use IPC::Shareable;
use Data::Printer;

IPC::Shareable->clean_up;


my $sharevar1 = "a";
my $sharevar2;


print "A: $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);


my $glue1 = 'glu1';
my $glue2 = 'glu2';

my %options = (
  create    => 1, #'yes',
  exclusive => 0,
  mode      => 0644, #0644,
  destroy   => 1, # 'yes',
);

my $sharevar_handle1 = tie $sharevar1, 'IPC::Shareable', $glue1 , \%options ; #

print "B1: $sharevar1 $sharevar2 - $sharevar_handle1\n";

my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #

print "B2: $sharevar1 $sharevar2 - $sharevar_handle2\n";

p($sharevar1);
p($sharevar2);


$sharevar1 = "b";
#~ $sharevar1 = "AOE" . \$sharevar2;
$sharevar2 = 20;

print "C: ";
print "- $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);

当我运行它时,我得到如下输出 - 这是预期的:

Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 13.
A: a 
"a"
undef
Use of uninitialized value $sharevar1 in concatenation (.) or string at tt.pl line 30.
Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 30.
B1:   - IPC::Shareable=HASH(0xa1dc1b8)
Use of uninitialized value $sharevar1 in concatenation (.) or string at tt.pl line 34.
Use of uninitialized value $sharevar2 in concatenation (.) or string at tt.pl line 34.
B2:   - IPC::Shareable=HASH(0xa215b10)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
C: - b 20
"b" (tied to IPC::Shareable)
20 (tied to IPC::Shareable)

 

但是,如果现在我尝试取消注释“$sharevar1 = "AOE" . \$sharevar2;”行,同时注释掉上面的“$sharevar1 = "b";”;那么我得到的输出几乎是相同的,除了最后:

...
B2:   - IPC::Shareable=HASH(0x852fb20)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
Can't use string ("AOESCALAR(0x836bf88)") as a SCALAR ref while "strict refs" in use at /usr/local/share/perl/5.10.1/IPC/Shareable.pm line 741.
C: $ 

现在,问题是这个“不能使用字符串...”实际上会导致崩溃...显然,如果 tied 变量曾经通过 \ 获得引用,它会得到一个类似的值SCALAR(0x836bf88) 作为一个字符串,显然后来被 Perl 解释为一个地址...?!

我认为在这种情况下 Perl 会匹配字符串的起始部分 (SCALAR(...) - 所以我试图通过在字符串 "AOE" 前面添加字符串来作弊 - 但奇怪的是,Perl 仍然注意到 (好像它正在为“0x withing parenthesis”寻找一些正则表达式,有点匹配):“不能使用字符串(“AOESCALAR(0x836bf88)”)作为SCALAR ref”......

 

我的问题是 - 我对 Perl 和 IPC::Shareable 如何解释地址(否则存储为“字符串”)正确的推理(不,请参阅下面的编辑;是的,请参阅post);不管是不是,我将如何将地址存储到 IPC::Shareable 中?

非常感谢您的任何回答, 干杯!

编辑:嗯,显然,打印包含字符串地址的字符串变量通常都可以正常工作 - 所以这个问题是 IPC::Shareable 特定的,我猜:

  DB<1> $ttt = "aa"
  DB<2> p $ttt
aa
  DB<3> $eee = \$ttt
  DB<4> p $eee
SCALAR(0xa382668)
  DB<5> $eee = "erw".\$ttt
  DB<6> p $eee
erwSCALAR(0xa382668)
  DB<7> q

【问题讨论】:

【参考方案1】:

如果您升级到IPC::Shareable 的最新版本 (0.60),我可以为您提供更好的帮助。我目前无法使用 Unix 机器来尝试此操作,但当前版本的第 741 行没有任何意义。

您应该知道,当您处理绑定变量时,您只是在与一个看起来像 Perl 变量的标准 API 交互。因此,在写 $sharevar1 = "AOE" . \$sharevar2 时,您实际上是在调用 IPC::Shareable::STORE($sharevar1, "AOE" . \$sharevar2),它几乎可以做它想做的事情。

我在模块中看到的是检查要分配的值(给绑定的标量)是否为参考值的代码,如果是,则将其绑定到 IPC::Shareable(如果尚未绑定)。取消引用值时使用的类型是通过检查字符串化引用与/SCALAR/ 等建立的,尽管我不知道它如何应用于您所看到的行为(我希望字符串'AOESCALAR(0x836bf88)' 被识别为不是参考,因此不受正则表达式检查)我相信它是有贡献的。也许这是我的版本中已修复的问题?

这种方法有很大的错误空间,尤其是与其他类相关的变量会完全抛弃整个事情。我建议你升级,看看最新版本是否支持你想做的事情。

请记住,这与核心 Perl 无关,而与模块不完全模拟 Perl 标量的接口有关。

【讨论】:

嗨@Borodin,感谢您的回答!我试过更新,perl 说:IPC::Shareable is up to date (0.6). 我已经更新了my post;我可以确认,只要不存在大写“SCALAR”,就可以打印变量(即使是小写的“scalar”);我也希望“被认为不是参考”,但显然不是这样,至少在我的 Ubuntu 机器上是这样。再次非常感谢 - 干杯!【参考方案2】:

好吧,原来我错了:)

事实证明,这个问题 - 毕竟 - 与字符串解析有关;即检查大写的关键字SCALAR;这是OP中代码的相应更改部分:

p($sharevar1);
p($sharevar2);


#~ $sharevar1 = "b";
#~ $sharevar1 = substr "AOE" . \$sharevar2, 2, 7; # Can't use string ("ESCALAR") as a SCALAR ref
#~ $sharevar1 = substr "AOE" . \$sharevar2, 5, 10; # "ALAR(0x878", passes OK
$sharevar1 = lc \$sharevar2; # lowercase works too
$sharevar2 = 20;

print "C: ";
print "- $sharevar1 $sharevar2\n";
p($sharevar1);
p($sharevar2);

请注意,只要您有SCALAR,即使您没有地址数字(如“ESCALAR”),也会引发严格使用错误。

但是,如果关键字SCALAR 不完整存在——即使它是小写的——那么错误就会消失;现在是终端日志的结尾:

...
B2:   - IPC::Shareable=HASH(0x9ca2e58)
undef (tied to IPC::Shareable)
undef (tied to IPC::Shareable)
C: - scalar(0x9adef88) 20
"scalar(0x9adef88)" (tied to IPC::Shareable)
20 (tied to IPC::Shareable)

嗯,希望就是这样 - 但由于我还不太了解这种机制,欢迎任何更好的澄清, 干杯!


编辑:刚刚发现另一件事;有时你可能会这样做:

my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #
print($sharevar2);

我刚刚注意到有时(但并非总是如此,也不能真正说出何时); tie 而不是 'undef',会将 $sharevar2 变量设置为“SCALAR()”或“ARRAY()”之类的东西——在这种情况下,print($sharevar2); 语句将失败。

您不能以其他方式进行调试,但要在 $sharevar2 上使用 Data::Printerp()(因为无论如何尝试打印都会失败) - 而是在 $sharevar_handle2 上使用:

my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; #
print "2 "; p($sharevar_handle2);

...然后输出可能是这样的:

...
2 IPC::Shareable  
    Parents       Exporter
    Linear @ISA   IPC::Shareable, Exporter
    public methods (31) : ....
    private methods (11) : ....
    internals: 
        _data   \ "ARRAY(0xa21e788)",
        _iterating   "",
...

在这种情况下,您确定$sharevar2 设置为“ARRAY(0xa21e788)”,因此当尝试print 时总是会失败。请注意,这样的事情可能是由于有一个命令将$sharevar2 分配给一个引用(即= \$somevar;在代码中很晚;这种因果关系可能并不总是显而易见的。

对于临时修复,只需在 tie 之后将“行为不端”变量设置为 undef - 这样可以更轻松地跟踪分配给引用的位置:

my $sharevar2;
my $sharevar_handle2 = tie $sharevar2, 'IPC::Shareable', $glue2 , \%options ; 
# if here $sharevar2 somehow becomes "ARRAY(0x88417c8)" instead of undef; reset
print "1 "; p($sharevar_handle2); # would show "ARRAY(0x88417c8)"
$sharevar2 = undef;
print "2 "; p($refvarstr_handle); # should show undef
p($sharevar2); # should not crash, cause it's now ARRAY anymore, but undef

还相关:can't use string as a SCALAR ref while strict refs - perlmonks.org

【讨论】:

以上是关于IPC::Shareable 变量,“不能使用字符串...作为 SCALAR ref..”和内存地址的主要内容,如果未能解决你的问题,请参考以下文章

IPC::Shareable 是不是适用于受祝福的对象?

检查 IPC 共享锁

Perl IPC 不使用共享内存?

<Image source=/> 为啥不能使用字符串变量? (反应原生)

剑指offer(三十二)之把字符串转换成整数

猫鼬不能使用字符串类型填充