当前位置:网站首页>d中shared用法
d中shared用法
2022-08-09 17:01:00 【fqbqrr】
原文
永远不要使用__gshared.这是明显安全漏洞.改为使用shared.
如果使用时遇见shared的编译错误,那是编译器在警告你.应该认真考虑线程安全,然后才在正确的位置抛弃shared.
使用__gshared,编译器假装没有看到变量是共享的.并除非仔细思考,保证会生成竞争.
顺便,有优先__gshared而非shared的情况吗?似乎许多新手在用__gshared.
我不完全同意该点,这仅取决于你用法.一般,你应该使用shared,但__gshared有意义.只是在多线程可更改时才有问题,但如果它仅从单线程更改但从多线程读取,则一般不是问题.
总之:
单写/单读?用__gshared
单写/多读?用__gshared
多写/单读?用shared
多写/多读?用shared
如果与C对接,则需要__gshared.但是,是的,这里应该使用shared.
__gshared表现不错,但我优先用std.concurrency,示例:
import std.stdio;
import std.concurrency;
import core.thread;
struct Result {
int value;
}
struct Done {
}
void run()
{
bool done = false;
while (!done) {
writeln("运行子线程");
receiveTimeout(1.seconds,
(Done msg) {
done = true;
});
}
// `发送`结果给所有者
// 假定,线程在上面循环中产生结果
ownerTid.send(Result(42));
}
void main()
{
auto worker = spawn(&run);
Thread.sleep(5.seconds);
worker.send(Done());
auto result = receiveOnly!Result();
writeln("结果:", result);
}
所有这些都可能是竞争条件.
这是单写单读的:
align(64) static struct S
{
align(1):
ubyte[60] off;
ulong x = 0;
}
__gshared S s;
void main()
{
import core.thread: Thread;
import std.conv: to;
new Thread(() {
foreach (i; 0 .. uint.max)
{
s.x = 0;
s.x = -1;
}
}).start();
foreach (i; 0 .. uint.max)
{
auto x = s.x;
assert(x == 0 || x == -1, to!string(x, 16));
}
}
如果你知道如何安全地访问变量,则可用shared.我坚持:永远不要使用__gshared.
快速测试表明extern(C) extern shared工作很好.
据我所知,__gshared仅在,你想在单线程程序中访问共享C变量时才工作良好.然后,如果稍后用多线程,你仍然会失败.
所以,永远不要(在多线程代码中)使用__gshared.
C没有共享概念,所以不是正确类型.加上shared只是假,并会导致麻烦.最好明确说明.
并不是说你应该自由使用__gshared,或只在D中使用.而是说永远不应使用它,这是错误的.
废话.在共享变量上加shared不是"说谎".C是否区分并不重要.但D重要.
如果你可识别出__gshared的有效用例,并用它编写正确代码,则你就知道什么时候不听我的.
其他人,永远不要使用__gshared.__gshared和-boundscheck=off一样糟糕.它们都是明显的安全漏洞.
auto x=s.x;
你的问题在此,而不是因为它是__gshared.
你复制了该值,显然可同时更改它,这是常识.
你不应这样使用它.而应该直接访问s.x.
而用共享,如果读取线程时先锁定,则结果相同,且在更改前会读取并处理该值.
读x时,就改了x.
auto x = s.x;
assert(s.x == 0 || s.x == -1, to!string(s.x, 16));
//多个竞争替代原来的1个竞争,且不能定位问题
shared并不能解决条件竞争,这是对的.如果没有-preview=nosharedaccess,则无区别.所以不妨使用shared.
但是有了-preview=nosharedaccess,代码不再编译,你不得不考虑如何安全访问共享数据.哪个好?
所以:永远不要使用__gshared,总是用-preview=nosharedaccess.
如果你有更好抽象且仔细锁定访问数据,但C不行,如果想访问C全局变量,应使用__gshared,因为这就是它的用途.使用shared,帮不了你.
使用__gshared来共享数据给C,与使用-boundscheck=on发送数组到无此类限制的C中一样安全.
这里结论真的应该是,不要使用C.
不,使用shared确实可以帮你.
C没有shared限定符,但C程序员仍然必须考虑线程安全.调用C函数或访问C全局变量必须考虑多线程.shared加上(-preview=nosharedaccess)迫使你考虑合同是什么.__gshared没有.
不,这不对.C总是不安全的,这是正确的,但不重要.关键是你在D端可以/不能做什么.
-boundscheck=on,不会轻易在D端搞砸.C端还是可以乱七八糟的.-boundscheck=off,很容易在D端搞砸.shared,不会轻易在D端搞砸.C端还是可以乱七八糟的.__gshared,很容易在D端搞砸.
shared让你感觉该语言帮你预防问题.同样,对C,这是假的.
边界在C和D中的定义相同,有指针和大小,你不能超过那个大小.是的,数据以不同的方式传达,但这很容易理解和使用.shared(加上-preview=nosharedaccess),阻止你上场.不会犯规.不能伤害自己.可通过强制转换告诉编译器(1)你确定要玩,及(2),你将按C端的规则玩.__gshared只是让你在球场上奔跑.不知道规矩?编译器不在乎.玩得开心打断你的腿.
用__gshared:
extern(C) extern __gshared int x;
void fun() {
x = 42; }
//编译,条件竞争
我甚至未发现我在做危险事情,因为第一次天真的通过了编译且似乎工作正常.
使用shared(加-preview=nosharedaccess):
extern(C) extern shared int x;
void fun() {
x = 42; } /* 错误 */
如果查看文档,会发现关于正确用法.正如你所建议的,我想出了:
extern(C) extern shared int x;
void fun() {
properlyUse(&x, 42); }
//仍错误,但共享.
我被迫更多地考虑线程安全.这里可以丢弃shared,因为调用了线程安全的properlyUse函数.所以:
extern(C) extern shared int x;
void fun() {
properlyUse(cast(int*) &x, 42); }
//编译,正确.
用__gshared这不大会发生.没有转换的调用properlyUse可能更好,但我不信人们记得在没有编译器对他们大喊大叫时就使用该函数.
即使他们第一次做对了,随着时间推移,他们也一定会失败.当简单的,错误的代码编译时,它肯定会进入源文件.
很难做到正确的线程安全.需要从编译器中获得的所有帮助.__gshared提供零帮助.shared至少高亮了有趣的地方.
边栏推荐
猜你喜欢
随机推荐
[Pycharm easy to use function]
WinForm(四)一种实现登录的方式
HarmonyOS - 基于ArkUI (JS) 实现图片旋转验证
进程的两种创建方式,join方法,进程间的数据隔离,队列,进程间的通信IPC机制,生产者消费者模型,守护进程,僵尸进程,孤儿进程,互斥锁
approach和method的区别
The senior told me that the MySQL of the big factory is connected through SSH
微软 .NET Core 3.1 年底将结束支持,请升级到.NET 6
An in-depth understanding of the implementation principle of Hybrid
[Code Audit] - PHP project class RCE and files include download and delete
【Pycharm好用功能】
【机器学习】回归树生成过程及举例理解
动态RDLC报表(六)
从事软件测试一年,只会基础的功能测试,怎么进一步学习?
SkiaSharp 之 WPF 自绘 粒子花园(案例版)
SSM框架练手项目,高企必备的管理系统—CRM管理系统
Can't install the Vmware virtual machine on the Ark Kai server?
2022 全球 AI 模型周报
动手学深度学习_全卷积网络 FCN
以技术御风险,护航云原生 | 同创永益 X 博云举办产品联合发布会
MASA Stack 第三期社区例会



![[极客大挑战 2019]HardSQL](/img/99/74cd7c56b3915db371ebc7811f2987.png)





