Skip to content

Commit 61cb77d

Browse files
committed
ファイル追加。
1 parent a650455 commit 61cb77d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+5549
-0
lines changed

article.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#article
2+
3+
| |
4+
|----------------|
5+
|<br/> |

article/at_thread_exit.md

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
#_at_thread_exit
2+
<h1>_at_thread_exit系の関数が存在している理由</h1>
3+
4+
[<future>](/reference/future.md)[<condition_variable>](/reference/condition_variable.md) には、*_at_thread_exit という名前の関数が定義されている。
5+
6+
namespace std {
7+
8+
void [notify_all_at_thread_exit](/reference/condition_variable/condition_variable/notify_all_at_thread_exit.md)([condition_variable](/reference/condition_variable/condition_variable.md)& cond, [unique_lock](/reference/mutex/unique_lock.md)<[mutex](/reference/mutex/mutex.md)> lk);
9+
10+
11+
12+
13+
` template <class R>`
14+
15+
` class [promise](/reference/future/promise.md) {`
16+
17+
` public:`
18+
19+
` ...`
20+
21+
void [set_value_at_thread_exit](/reference/future/promise/set_value_at_thread_exit.md)(const R& r);
22+
23+
void [set_exception_at_thread_exit](/reference/future/promise/set_exception_at_thread_exit.md)([exception_ptr](/reference/exception/exception_ptr.md) p);
24+
25+
};
26+
27+
<span style='font-family:Arial,Verdana,sans-serif'>
28+
</span>
29+
30+
template <class R, class... ArgTypes>
31+
32+
class [packaged_task](/reference/future/packaged_task.md)<R(ArgTypes...)> {
33+
34+
35+
public:
36+
37+
...
38+
39+
void [make_ready_at_thread_exit](/reference/future/packaged_task/make_ready_at_thread_exit.md)(ArgTypes... args);
40+
41+
};
42+
43+
44+
}
45+
46+
47+
これらの関数は、スレッドローカル記憶域が破棄された後に通知を行なったり、状態を変更する。
48+
49+
なぜこれらの関数が必要なのかというと、もしこれらの関数が無い場合、[thread](/reference/thread/thread.md)::[detach](/reference/thread/thread/detach.md)() されたスレッド上で、スレッドローカル記憶域との同期を取る方法が無くなってしまうからである。
50+
51+
デタッチされたスレッドにおいて、スレッドローカル記憶域にあるオブジェクトがいつ破棄されるかという規定は無い。そのため、未定義動作を含まずにこれらのオブジェクトを破棄するのは難しい。
52+
53+
例えば、以下のようなケースで問題になる。
54+
55+
#include <type_traits>
56+
57+
#include <future>
58+
59+
#include <thread>
60+
61+
#include <iostream>
62+
63+
64+
65+
template<class F>
66+
67+
std::future<typename std::result_of<F()>::type> spawn_task(F f) {
68+
69+
typedef typename std::result_of<F()>::type result_type;
70+
71+
std::packaged_task<result_type ()> task(std::move(f));
72+
73+
std::future<result_type> future(task.get_future());
74+
75+
std::thread th(std::move(task));
76+
77+
th.detach();
78+
79+
return future;
80+
81+
}
82+
83+
84+
85+
86+
87+
struct Hoge {
88+
89+
~Hoge() { std::cout << "Hoge destructor" << std::endl; }
90+
91+
};
92+
93+
94+
95+
int f() {
96+
97+
thread_local Hoge h;
98+
99+
return 42;
100+
101+
}
102+
103+
104+
105+
int main() {
106+
107+
std::future<int> res(spawn_task(f));
108+
109+
std::cout << res.get() << std::endl;
110+
111+
}
112+
113+
出力:
114+
115+
42Hoge destructor
116+
117+
118+
119+
120+
121+
122+
spawn_task は、渡された任意の処理を別スレッドで行なう一般的な関数である。関数内部でスレッドを作り、デタッチを行なっている。
123+
124+
125+
出力は、main 関数での出力と、Hoge デストラクタでの出力が混在している。これはスレッドローカル記憶域と future オブジェクトが正しく同期されていないからである。そのため、これ以外の出力も起こり得る。
126+
127+
これは *_at_thread_exit 系の関数を利用することで修正できる。
128+
129+
#include <type_traits>
130+
131+
#include <future>
132+
133+
#include <thread>
134+
135+
#include <iostream>
136+
137+
138+
139+
template<class R>
140+
141+
void task_executor(std::packaged_task<R> task) {
142+
143+
task.<color=ff0000>make_ready_at_thread_exit</color>(); // operator() を呼び出す代わりに make_ready_at_thread_exit() を呼び出す。
144+
145+
}
146+
147+
148+
149+
template<class F>
150+
151+
std::future<typename std::result_of<F()>::type> spawn_task(F f) {
152+
153+
typedef typename std::result_of<F()>::type result_type;
154+
155+
std::packaged_task<result_type ()> task(std::move(f));
156+
157+
std::future<result_type> future(task.get_future());
158+
159+
std::thread th(task_executor, std::move(task));
160+
161+
th.detach();
162+
163+
return future;
164+
165+
}
166+
167+
168+
169+
170+
171+
struct Hoge {
172+
173+
~Hoge() { std::cout << "Hoge destructor" << std::endl; }
174+
175+
};
176+
177+
178+
179+
int f() {
180+
181+
thread_local Hoge h;
182+
183+
return 42;
184+
185+
}
186+
187+
188+
189+
int main() {
190+
191+
std::future<int> res(spawn_task(f));
192+
193+
std::cout << res.get() << std::endl;
194+
195+
}
196+
197+
出力:
198+
199+
Hoge destructor
200+
201+
42
202+
203+
このプログラムの出力は、必ずこの通りになる。つまり、確実にスレッドローカル記憶域のオブジェクトが破棄された後に res.get() の結果が出力される。
204+
205+
206+
##参考
207+
208+
- [futureとpromiseのあれこれ(理論編) - yohhoyの日記](http://d.hatena.ne.jp/yohhoy/20120131/p1)
209+
- [N3070 - Handling Detached Threads and thread_local Variables](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3070.html)

0 commit comments

Comments
 (0)