作者Lipraxde (静夜)
看板C_and_CPP
标题[问题] 关於 llvm 的 ThreadSafeModule 的疑惑
时间Sat Apr 13 16:16:30 2019
最近在用 llvm 的 OrcJIT,要将 Module 丢进去跑之前要转成一个叫
ThreadSafeModule 的东东,再用 llvm::orc::IRLayer add 进去
ThreadSafeModule 大概长这样:
class ThreadSafeModule {
public:
ThreadSafeModule() =
default;
ThreadSafeModule(ThreadSafeModule &&Other) =
default;
ThreadSafeModule &
operator=(ThreadSafeModule &&Other);
ThreadSafeModule(std::unique_ptr<Module> M, std::unique_ptr<LLVMContext> Ctx)
: M(std::move(M)), TSCtx(std::move(Ctx)) {}
ThreadSafeModule(std::unique_ptr<Module> M, ThreadSafeContext TSCtx)
: M(std::move(M)), TSCtx(std::move(TSCtx)) {}
Module *getModule() {
return M.get(); }
const Module *getModule()
const {
return M.get(); }
ThreadSafeContext::Lock getContextLock() {
return TSCtx.getLock(); }
explicit operator bool();
private:
std::unique_ptr<Module> M;
ThreadSafeContext TSCtx;
};
OrcJIT 跑完後如果中间有设 setNotifyCompiled 就会把 ThreadSafeModule 丢回来
然後 Module 就变成 ThreadSafeModule
把 ThreadSafeModule 释放掉连带着 Module 也释放掉了
问题(Question):
1. 这个 ThreadSafeModule 为什麽要弄得像黑洞一样?不把 Module release 出来
2. 它的 member function 'getModule',为什麽要写一个有 const 一个没有两个版本?
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 140.113.210.55
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1555143401.A.118.html
1F:→ loveme00835: 你就要看呼叫 getContextLock() 的地方了, 他比较像 04/14 00:46
2F:→ loveme00835: "Module with a mutex" 的概念, 不过他都 move 给你 04/14 00:47
3F:→ loveme00835: 注册的 NotifyCompiledFunction, 等於生杀大权都交给 04/14 00:50
4F:→ loveme00835: 你, 其实就等於已经 release. 第 2 个是语言的问题 04/14 00:50
5F:→ loveme00835: , 为了传递和 this 相同的 const 语意, 简单说如果透 04/14 00:54
6F:→ loveme00835: 过 const ThreadSafeModule& 拿到的 Module 物件也必 04/14 00:54
7F:→ loveme00835: 须是 const 的理由是: const T& 在你 statement 结束 04/14 00:56
8F:→ loveme00835: 前保证的语意是 "物件一直都存在", 所以当 this 给你 04/14 00:57
9F:→ loveme00835: 保证但回传的 Module 不保证是很奇怪的 (因为 owning 04/14 00:57
10F:→ loveme00835: 语意), 另一方面 this 不保证但 Module 保证也很奇怪 04/14 00:58
11F:→ loveme00835: 这表示即使它给你 Module, 它还是可以偷偷把 Module 04/14 00:59
12F:→ loveme00835: 给 delete 掉 04/14 00:59
谢谢回覆,问题1的话生杀大权是拿回来了,不过变成另一种东西...有一种被强迫的感觉
问题2呢,想一想的确从 const 物件拿出来的东西,既然交给它管了那也该是 const。不
过「const T& 在你 statement 结束前保证的语意是 "物件一直都存在"」有点难懂,是
说 reference 到一个 const T,这个 reference 一直都有效的意思?
※ 编辑: Lipraxde (140.113.56.71), 04/14/2019 11:48:26
13F:→ loveme00835: 是啦, 不过既然你能把它的资源 move 到别边就不是什 04/14 16:21
14F:→ loveme00835: 麽大问题. 问题 2 涉及的不只是 constness 的语意, 04/14 16:23
15F:→ loveme00835: 而且还包含 lifetime 的保证, 你可以看这个范例 04/14 16:24
17F:→ loveme00835: 收到一个 const T&, 你需要保证/可以假设它在某段区 04/14 16:28
18F:→ loveme00835: 间内都是活着的(意即可以透过这个 ref 去存取它) 04/14 16:29
19F:→ loveme00835: 所以你可以想像如果两种版本的 getModule() 回传值和 04/14 16:57
20F:→ loveme00835: this 不同调的冲突在哪里 (用多个 thread 的角度来看 04/14 16:58
21F:→ loveme00835: ) 至於为什麽要有两个版本? 其实就是想两种不同语意 04/14 16:59
22F:→ loveme00835: 下都能叫用, 只是能提供的保证不同 04/14 16:59
例子我懂了, const T& 延长了那个暂时物件的 lifetime,保证它一定存在
不过它这里是 getModule 是传回 pointer 耶,用 pointer 会有保证的效果吗?
多个 thread 的情况,要获得保证一定要先呼叫 getContextLock 才行吧?
※ 编辑: Lipraxde (140.113.56.71), 04/14/2019 20:29:06
23F:→ loveme00835: 对指标 de-ref 也是一样的, 除了原本 lifetime 的保 04/14 21:08
24F:→ loveme00835: 证, 另外还有 nullable 的语意, 算是不好的介面设计 04/14 21:09
25F:→ loveme00835: 多个 thread 的情况下, 简单举个例子: 对於同样的int 04/14 21:09
26F:→ loveme00835: 物件, thread a 拿到的如果是 int*, thread b 拿到的 04/14 21:10
27F:→ loveme00835: 是 const int&, 那麽这边就有一个隐含的语意: 在 b 04/14 21:11
28F:→ loveme00835: 结束存取之前, a 都不可以把这个物件给 delete 掉 04/14 21:11
29F:→ loveme00835: 不过这算是和 execution model 相关的讨论, 简单的作 04/14 21:14
30F:→ loveme00835: 法就是 read/write 都用锁, 存取前确认合法性, 这样 04/14 21:14
31F:→ loveme00835: 就能确保正确性 04/14 21:15
假如是用 int& 就没有这个保证了吗?
我看了 Lifetime of temporaries bound to references,里面写到:
For any statement explicitly binding a reference to a temporary, the lifetime
of all temporaries in the statement are extended to match the lifetime of the
reference.
似乎跟有没有 const 修饰没有关系呀,还是说这个是在讲不同的事?
※ 编辑: Lipraxde (140.113.56.71), 04/15/2019 00:03:32
32F:→ loveme00835: bind to temporary 是一回事, 而延长 lifetime 就是 04/15 00:09
33F:→ loveme00835: 为了达成我所说的保证, 也就是 const T& 背後带来的 04/15 00:10
34F:→ loveme00835: 目的 04/15 00:10
35F:→ loveme00835: 不只是 "有/无 const" 这样表面上的问题 04/15 00:11
36F:→ loveme00835: int& 算是 caller/callee 之间需要协议好这个物件的 04/15 00:42
37F:→ loveme00835: 生命周期是如何, 也许到 callee 的某个时间点就无法 04/15 00:43
38F:→ loveme00835: de-ref, 而 const int& 给的语意更为强烈, 也就是在 04/15 00:44
39F:→ loveme00835: callee 呼叫结束前物件都是可用的, 除了无法透过 ref 04/15 00:45
40F:→ loveme00835: 去 modify, 其实 caller 还有一个责任是 callee 观察 04/15 00:45
41F:→ loveme00835: 到的物件行为到呼叫结束前必须不变 04/15 00:46
就我对 reference 的理解来说:
int&
// 参考到某个 int
const int&
// 参考到某个 const int
考虑到 lifetime 的保证,那就是:
int&
// 参考到某个 int,这个参考可能在某个时间点後就不能相信它了
const int&
// 参考到某个 const int,由於目标是个 const,不会变,所以【可以/要】
// 保证这个参考有效
是说这个 const 用来修饰 int,为什麽要去影响 reference 的有效性?
可以保证有效,但是一定要做出这个保证?
※ 编辑: Lipraxde (140.113.56.71), 04/15/2019 02:13:02
42F:→ loveme00835: 在函式中, 我们把 callee 以及 caller 角色分开, 04/15 02:58
43F:→ loveme00835: callee 加上 const 修饰, 即是和 caller 要求对应的 04/15 02:59
44F:→ loveme00835: 保证, 当然 caller 可以不理会, 譬如接收 const Foo& 04/15 03:00
45F:→ loveme00835: 然後进行两次 foo.getXXX() 呼叫, 这时候 callee 预 04/15 03:01
46F:→ loveme00835: 期不管呼叫再多次得到的值都要是相同的. 这就是加上 04/15 03:02
47F:→ loveme00835: const 会需要 caller 做出的保证, 所以不单单只是 04/15 03:02
48F:→ loveme00835: callee 不想改它的值这麽简单 04/15 03:02
49F:→ loveme00835: 所以简单说 const 不只是描述 "存取方式", 也描述了 04/15 03:05
50F:→ loveme00835: "存取的一致性", 当然也包含 lifetime 04/15 03:05
51F:→ loveme00835: 那回来看 getModule() 回传 const Module* 即是它给 04/15 03:13
52F:→ loveme00835: 出的保证: 在 this 为 const ThreadSafeModule* 的情 04/15 03:13
53F:→ loveme00835: 况下 (const member function), 取得的 Module 物件 04/15 03:13
54F:→ loveme00835: 行为是不变的 (包含 lifetime) 04/15 03:13
56F:→ Lipraxde: 接收 const Foo&,呼叫 foo.getXXX()多次,预期拿到相 04/15 03:40
57F:→ Lipraxde: 同的物件,由於这个物件属於 foo,所以也要是 const 物 04/15 03:40
58F:→ Lipraxde: 件,不然 foo 就失去 const 的性质了 04/15 03:40
59F:→ Lipraxde: 这样说得算是完整了吗? 04/15 03:53
60F:→ loveme00835: 对喔, 这是因为 owning 语意的关系, 如果这个物件不 04/15 03:58
61F:→ loveme00835: 属於 foo, 那就没必要维持 const 语意 04/15 03:59
62F:→ Lipraxde: 既然 callee 要求对应的保证,那 Compiler 可以优化它 04/15 04:04
63F:→ Lipraxde: ?可是加了优化後得到的输出还是有看到 i 被改成 1。Co 04/15 04:04
64F:→ Lipraxde: mpiler 聪明的判断出这个 caller 没做出相应的保证,抑 04/15 04:04
65F:→ Lipraxde: 或是这个保证只是给 programmer 看的? 04/15 04:04
66F:→ loveme00835: 因为是参考(指标也是)所以能做的优化有限, 但这个也 04/15 04:14
67F:→ loveme00835: 是 programmer 需要遵守, 属於语意层面的规范 04/15 04:15
感谢您花这麽多时间回覆,看来是因为 C 没有 owning 语意,我又忽略掉 const[A 还有
"存取的一致性" 这层意义,才会出现问题2。我应该把 C++ 当门新的语言学才是
※ 编辑: Lipraxde (140.113.56.71), 04/15/2019 20:59:08