Нарушение доступа с помощью getline в потоке + boost:: function

Я собирался написать класс, который считывает std::cin в потоке и вызывает обратный вызов, когда что-то вводится. Обратный вызов представляет собой boost::function. Код запускается, если у меня есть только std::getline (std::cin, command); , но вылетает с «нарушением доступа», если я добавляю строку if(this->m_receiveHandler != NULL). Я действительно не могу понять, что происходит, поэтому я свел проблему к следующему тесту.

Проблема не полностью детерминированная, иногда могу ввести строку или две, иногда сразу вылетает. Последнее, что выводит программа, это всегда "обработчик приемника доступа".

class InputReader
{
private:
    boost::function<void (const char*, unsigned int) > m_receiveHandler;
    boost::thread m_receiveThread;

    void receiveLoop(void)
    {

        while(true)
        {
            std::string command;
            std::getline (std::cin, command);
            std::cout << "access receiver handler" << std::flush;               
            if(this->m_receiveHandler != NULL)
            {
            }           
        }

    }

public:
    InputReader()
    {
        m_receiveThread = boost::thread(boost::bind(&InputReader::receiveLoop, this));
    }


};

TEST(InputReaderTest, WaitInfinite)
{
    InputReader reader;
    while (true) {};
}

Вы видите что-то не так с этим кодом?

РЕДАКТИРОВАТЬ: я компилирую с GCC 4.3.2 на Suse Linux с Boost 1.49.


person Philipp    schedule 17.04.2013    source источник
comment
m_receiveHandler не указатель, можно смело сравнивать с NULL? Возможно, эта строка пытается создать boost::function из NULL. РЕДАКТИРОВАТЬ: существует empty() функция-член, которую вы могли бы использовать.   -  person BoBTFish    schedule 17.04.2013
comment
Я только что попробовал это с VS2010, за исключением TEST(), где я просто поместил InputReader read; в main() вместо этого и не получил ошибки сегмента после нескольких записей в stdin. Это весь код, в котором есть ошибки seg, и вы определенно перестроили его?   -  person hmjd    schedule 17.04.2013
comment
@BoBTFish: это немного странно, но есть недокументированный конструктор для преобразования константы нулевого указателя в пустую функцию; поэтому f != NULL дает то же логическое значение, что и f (или !f.empty(), если вам нравится многословие).   -  person Mike Seymour    schedule 17.04.2013
comment
Я предполагаю, что код вылетает в реальном коде, но не вылетает в приведенном выше тесте, не так ли? Это проблема времени жизни объекта: экземпляр InputReader уже уничтожен, когда вы пытаетесь получить доступ к его члену в потоке. Обратите внимание, что все предыдущие строки (getline) не обращаются ни к каким объектам-членам, поэтому они никогда не завершаются с ошибкой.   -  person Igor R.    schedule 17.04.2013
comment
@IgorR.: этот тест вылетает. Я еще не использовал класс в реальном коде.   -  person Philipp    schedule 17.04.2013
comment
@hmjd: спасибо за попытку. Я только что добавил информацию о своей платформе. Вопрос в следующем: означает ли это, что это проблема с GCC, или это означает, что Windows/VS2010 просто не обнаруживает проблему (если она есть)?   -  person Philipp    schedule 17.04.2013
comment
@BoBTFish: раньше я проверял документацию, в которой говорится, что сравнение с NULL допустимо. Теперь я также попробовал if(!m_receiveHandler.empty()), который дает тот же эффект.   -  person Philipp    schedule 17.04.2013
comment
@Филипп хорошо, я вижу. Тогда, может быть, у вас есть какое-то нарушение ODR? Убедитесь, что вы связываете и # include одну и ту же версию boost (возможно, на вашем компьютере установлено 2 версии и вы их случайно перепутали).   -  person Igor R.    schedule 17.04.2013


Ответы (1)


Я только что попробовал это с clang на OSX, и это работает (хотя ускорение было заменено на std). Что происходит, когда вы запускаете поток в другой общедоступной функции-члене? Переменная функции boost на самом деле является общей переменной между двумя потоками и, вероятно, должна быть защищена каким-либо примитивом параллелизма. Поток может на самом деле увидеть неполный снимок этого объекта. Это не объясняет, почему он работает два раза, прежде чем потерпеть неудачу. Если вы знаете, каким будет ReceiveHandler во время создания, и вам не нужно его менять, у вас есть возможность передать boost::function в качестве параметра потоку (копия или даже перемещение могут подойти).

person Wtr    schedule 17.04.2013