Вопрос по ссылкам на функции и темам - PullRequest
2 голосов
/ 02 января 2011

Я случайно тестировал std::thread на моей виртуальной машине Linux (GCC 4.4.5-Debian) с помощью этой тестовой программы:

#include <algorithm>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;

static int i=0;
void f( vector<int> &test)
{
    ++i;
    cout << "Push back called" << endl;
    test.push_back(i);
}

int main()
{
    vector<thread> t;
    vector<int> test;
    for( int i=0; i<1000; ++i )
    {
        t.push_back( thread( bind(f, test) ) );
    }
    for( auto it = t.begin(); it != t.end(); ++it )
    {
        (*it).join();
    }
    cout << test.size() << endl;
    for( auto it = test.begin(); it != test.end(); ++it )
    {
        cout << *it << endl;
    }

    return 0;
}

Почему вектор test остается пустым?Я делаю что-то глупое со ссылками (возможно) или это что-то с bind или с какой-то поточной проблемой?

Спасибо!

ОБНОВЛЕНИЕ : с помощью комбинированной помощиKos и villintehaspan Я «исправил» «проблему»:

#include <algorithm>
#include <thread>
#include <iostream>
#include <vector>
#include <functional>
using namespace std;

static int i=0;
void f( vector<int> &test)
{
    ++i;
    test.push_back(i);
}

int main()
{
    vector<thread> t;
    vector<int> test;
    for( int i=0; i<1000; ++i )
    {
        t.push_back( thread(f, std::ref(test)) );
    }
    for( auto it = t.begin(); it != t.end(); ++it )
    {
        (*it).join();
    }
    cout << test.size() << endl;
    for( auto it = test.begin(); it != test.end(); ++it )
    {
        cout << *it << endl;
    }

    return 0;
}

, которая печатает все значения в порядке и, кажется, работает нормально.Теперь остается только один вопрос: это просто удача (так называемое неопределенное поведение (TM)) или статическая переменная вызывает молчаливый мьютекс-подобный шаг в коде?

PS: я понимаю проблему «уничтожения многопоточности»здесь, и это не моя точка зрения.Я просто пытаюсь проверить надежность базовой std::thread функциональности ...

Ответы [ 2 ]

4 голосов
/ 02 января 2011

Выглядит как проблема с потоками.

Хотя я не уверен на 100%, следует отметить, что все 1000 потоков:

  • сделать ++i с тем же значением int (это не атомарная операция - здесь могут возникнуть проблемы, вместо этого вы можете использовать __sync_fetch_and_add(&i,1) (обратите внимание, что это расширение gcc не стандартное C ++);

  • сделать push_back одновременно на std::vector, который не является потокобезопасным контейнером AFAIK ... То же самое для cout Я думаю. Я считаю, что вам нужно использовать механизм блокировки вокруг этого (std::mutex возможно? Я до сих пор использовал только pthreads, но я считаю, что это то, что вам нужно).

Обратите внимание, что этот вид убивает любые преимущества использования потоков здесь, но это является следствием того факта, что вы не должны использовать несколько потоков одновременно для не поточно-безопасного объекта.


---- EDIT ----

У меня был Google на этом API потоков (к сожалению, его нет на моем tdm gcc 4.5 в Windows). Вне зависимости от:

thread( bind(f, test) )

Вы можете просто сказать

thread( f, test )

и таким образом передать произвольное количество аргументов.

Источник: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=422

Это также должно решить вашу проблему с копией вектора, который я раньше не замечал (+1 для @villintehaspam здесь).


На самом деле, еще одна вещь необходима, чтобы убедиться, что копия здесь не создана:

thread( f, std::ref(test) )

убедится, что вектор не скопирован.

Ух ты, я тоже запутался. :)

3 голосов
/ 02 января 2011

При связывании фактически создается копия вектора, так что каждый поток push_back имеет свою собственную копию (да, здесь это не поможет).Вам нужно предоставить потокам указатель или аналогичный, чтобы они использовали один и тот же вектор.Вы также должны убедиться, что используете защиту доступа, как предложено Косом.

Редактировать: После исправления для использования std :: ref вместо создания копии вектора проблема многопоточного доступа все еще остается.Я предполагаю, что единственная причина, по которой у вас сейчас нет проблем, заключается в том, что пример настолько тривиален (или, может быть, вы пробовали только в режиме отладки) - нет автоматической гарантии, что ++ является атомарным только потому, чтоint является статическим.

...