/* Define if gthreads library is available. */
/* #undef _GLIBCXX_HAS_GTHREADS */
となっていて、下記の様なthreadを使ったコードはコンパイル出来ないのですが
#include <atomic>
#include <thread>
#include <iostream>
std::mutex m ;
int x ;
void thread()
{
std::lock_guard<std::mutex> guard(m) ;
++x ; // 非アトミック操作
}
int main()
{
x = 0 ; // 初期値0
std::thread A( thread ) ;
std::thread B( thread ) ;
A.join() ; B.join() ;
std::cout << x << std::endl ; // 2であるべき
}
本の虫: C++0xのマルチスレッドとデータ競合が非常に難しい手を加えてやる事でビルド出来る事が分かった。まずはオプションを上書きしてやる。
「バリアー!」「デュクシ!」「ちょっ、お前、オレ、バリアー張...
http://cpplover.blogspot.com/2011/06/c0x.html
#define _GLIBCXX_HAS_GTHREADS 1
#define _GLIBCXX__PTHREADS 1
#define _POSIX_TIMEOUTS 1
次に、gthreadsが内部処理の為に定義しているスレッド識別子による比較関数を定義する
#include <pthread.h>
inline bool
operator<(const pthread_t& lhs, const pthread_t& rhs) {
return lhs < rhs;
}
この状態でとりあえずコンパイルは出来る。ただしgthreads無効でビルドされているのでスレッド操作関数の実体が無い。そこでthread.ccからコードを拝借する。
namespace std
{
namespace
{
extern "C" void*
execute_native_thread_routine(void* __p)
{
thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
thread::__shared_base_type __local;
__local.swap(__t->_M_this_ptr);
__try
{
__t->_M_run();
}
__catch(...)
{
std::terminate();
}
return 0;
}
}
void
thread::_M_start_thread(__shared_base_type __b)
{
if (!__gthread_active_p())
__throw_system_error(int(errc::operation_not_permitted));
__b->_M_this_ptr = __b;
int __e = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine, __b.get());
if (__e)
{
__b->_M_this_ptr.reset();
__throw_system_error(__e);
}
}
void
thread::join()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_join(_M_id._M_thread, 0);
if (__e)
__throw_system_error(__e);
_M_id = id();
}
}
全体のソースだとこんな感じ。
// {{{
// vi:set ts=8 sts=2 sw=2 tw=0:
// vim:fdm=marker fdl=0 fdc=0 fdo+=jump,search:
// vim:fdt=substitute(getline(v\:foldstart),'\\(.\*\\){\\{3}','\\1',''):
#define _GLIBCXX_HAS_GTHREADS 1
#define _GLIBCXX__PTHREADS 1
#define _POSIX_TIMEOUTS 1
#include <pthread.h>
inline bool
operator<(const pthread_t& lhs, const pthread_t& rhs) {
return lhs < rhs;
}
// }}}
#include <atomic>
#include <thread>
#include <iostream>
// {{{
namespace std
{
namespace
{
extern "C" void*
execute_native_thread_routine(void* __p)
{
thread::_Impl_base* __t = static_cast<thread::_Impl_base*>(__p);
thread::__shared_base_type __local;
__local.swap(__t->_M_this_ptr);
__try
{
__t->_M_run();
}
__catch(...)
{
std::terminate();
}
return 0;
}
}
void
thread::_M_start_thread(__shared_base_type __b)
{
if (!__gthread_active_p())
__throw_system_error(int(errc::operation_not_permitted));
__b->_M_this_ptr = __b;
int __e = __gthread_create(&_M_id._M_thread,
&execute_native_thread_routine, __b.get());
if (__e)
{
__b->_M_this_ptr.reset();
__throw_system_error(__e);
}
}
void
thread::join()
{
int __e = EINVAL;
if (_M_id != id())
__e = __gthread_join(_M_id._M_thread, 0);
if (__e)
__throw_system_error(__e);
_M_id = id();
}
}
// }}}
std::mutex m ;
int x ;
void thread()
{
std::lock_guard<std::mutex> guard(m) ;
++x ; // 非アトミック操作
}
int main()
{
x = 0 ; // 初期値0
std::thread A( thread ) ;
std::thread B( thread ) ;
A.join() ; B.join() ;
std::cout << x << std::endl ; // 2であるべき
}
これ、vimmerならfoldを使ってやれば
//
#include <atomic>
#include <thread>
#include <iostream>
//
int main() {
std::mutex m;
int x = 0;
std::thread A([&] {
for (int n = 0; n < 100; n++) {
std::lock_guard<std::mutex> guard(m);
++x;
std::cout << x << std::endl;
}
});
std::thread B([&] {
for (int n = 0; n < 100; n++) {
std::lock_guard<std::mutex> guard(m);
++x;
std::cout << x << std::endl;
}
});
A.join();
B.join();
}
こんな風に見えてちょっとはマシになる。これでmingw使ってthreadなプログラミングが出来ますね!lambda使えばこんなのも出来て、たのしーーーー!
#include <atomic>
#include <thread>
#include <iostream>
int main() {
std::mutex m;
int x = 0;
std::thread A([&] {
for (int n = 0; n < 100; n++) {
std::lock_guard<std::mutex> guard(m);
++x;
std::cout << x << std::endl;
}
});
std::thread B([&] {
for (int n = 0; n < 100; n++) {
std::lock_guard<std::mutex> guard(m);
++x;
std::cout << x << std::endl;
}
});
A.join();
B.join();
}