Perl:如果线程启动,JSON将失败

时间:2017-10-17 15:32:21

标签: json multithreading perl

有人可以告诉我为什么JSON在某些线程启动时无效吗?

public ColorPicker()
{
    InitializeComponent();
}

public SolidColorBrush SelectedColor
{
    get { return (SolidColorBrush)GetValue(SelectedColorProperty); }
    set { SetValue(SelectedColorProperty, value); }
}

public static readonly DependencyProperty SelectedColorProperty =
    DependencyProperty.Register(nameof(SelectedColor), typeof(SolidColorBrush), new UIPropertyMetadata(null));

正常工作并打印JSON字符串。但是将use strict; use warnings; use JSON; use threads; use threads::shared; sub th { } threads->create(\&th)->join() if $ARGV[0]; my $json = to_json({ val => "123"}); # WTF?!? print "$json\n"; 作为参数传递给脚本来创建线程,而1将失败并且

to_json

如果我使用encode_json insead,效果相同。 在JSON的联机帮助页上,单词thread不存在,我认为线程没有理由损害外部字符串转换。

???

3 个答案:

答案 0 :(得分:5)

JSON(.pm)只是JSON :: PP,JSON :: XS或Cpanel :: JSON :: XS的前端。

您在JSON :: XS中发现了一个错误。关于这一点,JSON :: XS的文档说:

  

(I-)THREADS

     

此模块不保证是ithread(或MULTIPLICITY-)安全,并且没有计划更改此模块。请注意,perl的内置所谓的theeads / ithreads已被正式弃用,不应使用。

[请注意,最后一部分不正确。官方立场实际上是:线程很难,所以你应该使用别的东西。这是非常值得怀疑的,因为替代方案可能同样困难。]

解决方法:使用其他后端之一(直接或通过JSON(.pm))。

$ PERL_JSON_BACKEND=JSON::XS 46793885 0
{"val":"123"}

$ PERL_JSON_BACKEND=JSON::XS 46793885 1
hash- or arrayref expected (not a simple scalar, use allow_nonref to allow this) at /home/ikegami/usr/perlbrew/perls/5.26.0t/lib/site_perl/5.26.0/JSON.pm line 170.

$ PERL_JSON_BACKEND=Cpanel::JSON::XS 46793885 1
{"val":"123"}

$ PERL_JSON_BACKEND=JSON::PP 46793885 1
{"val":"123"}

您可以在加载JSON之前添加以下内容来控制脚本:

BEGIN { $ENV{PERL_JSON_BACKEND} = 'Cpanel::JSON::XS' }

答案 1 :(得分:2)

这绝对与JSON和全局状态有关。 如果您requireimport JSON,在线程调用之后,它“有效”。

JSON::XS模块中的警告包括:

  

(I-)THREADS ^

     

此模块不保证是ithread(或MULTIPLICITY-)安全,并且没有计划更改此

非线程安全模块的'变通方法'是通过use(在'编译'时发生)加载它而不是require和在程序(线程)的并行实例启动后import(在运行时)。

E.g:

use strict;
use warnings;

use threads;
use threads::shared;

sub th { }

my $th = threads->create( \&th )->join;

## Just inside main thread
##can do this within individual threads instead if desired
require JSON;
JSON->import;


my $json = to_json({ val => "123" });    # WTF?!?
print "\n$json\n";

答案 2 :(得分:1)

我也遇到了这个问题(尝试使用多线程perl的JSON)。在没有启动后台线程的情况下,我的代码运行正常,但是在启动线程时遇到了同样的错误。

和您一样,我没有找到任何针对此错误文字的在线专有帮助。但是,在allow_nonref错误文本后,我在JSON :: XS的文档中找到了以下内容:

  

" OLD" VS. " NEW" JSON(RFC 4627 VS. RFC 7159)

     

TL; DR:出于安全考虑,JSON :: XS默认情况下不允许使用JSON>文本中的标量数据 - 您需要创建自己的JSON :: XS对象并启用   allow_nonref

my $json = JSON::XS->new->allow_nonref;

$text = $json->encode ($data);
$data = $json->decode ($text);

在您的情况下,您尝试调用to_json,它在内部创建一个JSON对象并在其上调用encode。不幸的是,它没有在其构造函数中指定allow_nonref。因此,要使代码正常工作,您可以执行以下操作:

use JSON::XS;

my $json_obj = JSON::XS->new->allow_nonref;
my $json = $json_obj->encode({ val => "123"});
print "$json\n";

我在阅读其他回复之前想出了这个解决方案,所以这些可能是更好的解决方案,但这至少应该让你以最小的改变来解决问题。