有人可以告诉我为什么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不存在,我认为线程没有理由损害外部字符串转换。
???
答案 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和全局状态有关。
如果您require
和import
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";
我在阅读其他回复之前想出了这个解决方案,所以这些可能是更好的解决方案,但这至少应该让你以最小的改变来解决问题。