2011/06/28

ダウンロード配布物となっている mingw の c++config.h では /* 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();
}

Posted at 17:39 | WriteBacks () | Edit
Edit this entry...

wikieditish message: Ready to edit this entry.






















A quick preview will be rendered here when you click "Preview" button.