mingw 4.6.1 атомарный сбой? - PullRequest
       43

mingw 4.6.1 атомарный сбой?

0 голосов
/ 14 декабря 2011

Итак, я обнаружил, что gcc уже имеет рабочую реализацию std::atomic, поэтому я хотел попробовать, вот мой пример с использованием Boost Thread 1.48 и std::atomic:

#include <iostream>
#define BOOST_THREAD_USE_LIB
#include <boost/thread.hpp>
#include <atomic>
#include <string>

using namespace std;
using namespace boost;

class Server
{
    public:
    atomic<bool> running;
    thread main_server_thread;


    void func1()
    {
        while(running)
        {
            //do stuff
        }
    }
    void func2()
    {
        while(running)
        {
            //do stuff
        }
    }
    void func3()
    {
        while(running)
        {
            //do stuff
        }
    }
    void func4()
    {
        string input;
        while(running)
        {
            //do stuff
            input.clear();
            getline(cin,input);
            if(input=="quit")running=false;
        }
    }

    void main_function()
    {
        thread thrd1(bind(&Server::func1,this));
        thread thrd2(bind(&Server::func2,this));
        thread thrd3(bind(&Server::func3,this));
        thread thrd4(bind(&Server::func4,this));

        while(running)
        {
            //do stuff
        }
        thrd1.join();
        thrd2.join();
        thrd3.join();
        thrd4.join();
    }

    Server()
    {
        running=true;
        main_server_thread = thread(&Server::main_function,this);
    }
};



int main()
{
    Server* serv = new Server();
    serv->main_server_thread.join();
    return 0;
}

Теперь, пока running остается true, все в порядке, но когда пользовательский ввод quit и running установлен на false, некоторые потоки заканчиваются, а некоторые - нет. Это происходит с оптимизацией и без нее. Это работает как задумано? В моем понимании атомики чтение не должно конфликтовать с записью, поэтому потоки должны увидеть running=false в какой-то момент.

EDIT: Разборка func1:

void func1()
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 ec 18                sub    $0x18,%esp
        {
            while(running)
   6:   90                      nop
   7:   8b 45 08                mov    0x8(%ebp),%eax
   a:   89 04 24                mov    %eax,(%esp)
   d:   e8 00 00 00 00          call   12 <__ZN6Server5func1Ev+0x12>
  12:   84 c0                   test   %al,%al
  14:   75 f1                   jne    7 <__ZN6Server5func1Ev+0x7>
            {
                //do stuff
            }
        }
  16:   c9                      leave  
  17:   c3                      ret    

1 Ответ

1 голос
/ 14 декабря 2011

Как показывает разборка, эта программа, скомпилированная с mingw, не обрабатывает running как атомарный: она загружается с обычным mov 0x8(%ebp),%eax без синхронизации.

Сравните с выводом gcc-4.6.2 в linux / x86_64:

_ZN6Server5func1Ev:      // Server::func1()
    jmp     .L78
.L79:
    // do stuff
.L78:
    mfence
    movzbl  (%rdi), %eax // load from `running`
    mfence
    testb   %al, %al
    jne     .L79
    ret

Либо mingw пока не поддерживает это, либо что-то отсутствует в его конфигурации.

...