boost :: scoped_lock не работает с локальной статической переменной? - PullRequest
4 голосов
/ 14 октября 2011

Я создал следующую программу-пример для работы с Boost Threading:

#pragma once
#include "boost\thread\mutex.hpp"
#include <iostream>

class ThreadWorker
{
public:
    ThreadWorker() {}
    virtual ~ThreadWorker() {}

    static void FirstCount(int threadId)
    {
        boost::mutex::scoped_lock(mutex_);
        static int i = 0;

        for(i = 1; i <= 30; i++)
        {
            std::cout << i << ": Hi from thread:  " << threadId << std::endl;
        }

    }

private:
    boost::mutex mutex_;
};

основной класс:

// ThreadTest.cpp
#include "stdafx.h"
#include "boost\thread\thread.hpp"
#include "ThreadWorker.h"

int _tmain(int argc, _TCHAR* argv[])
{
    boost::thread thread1(&ThreadWorker::FirstCount, 1);
    boost::thread thread2(&ThreadWorker::FirstCount, 2);
    boost::thread thread3(&ThreadWorker::FirstCount, 3);

    thread1.join();
    thread2.join();
    thread3.join();

    std::string input;
    std::cout << "Press <enter> to finish...\n";
    std::getline( std::cin, input );
    return 0;
}

Когда я запускаю это, я получаю следующий вывод:

1: Hi from thread:  1
1: Hi from thread:  3
2: Hi from thread:  3
...

Похоже, что поток 1 сначала идет туда, а затем поток 3. Разве scoped_lock не должен препятствовать тому, чтобы другие потоки входили в этот раздел кода? Разве первый поток, который запускает FirstCount (), не должен завершиться?

UPDATE

Одна вещь, которую я считаю неправильной в моем коде, это строка:

boost::mutex::scoped_lock(mutex_);

Я думаю, что это должно быть как:

boost::mutex::scoped_lock xyz(mutex_);

Как только я это делаю, он начинает жаловаться на то, что mutex_ не статичен. Почему это сработало в первую очередь, я не уверен. Изменение mutex_ на static дает мне ошибку компоновки:

1> ThreadWorker.obj: ошибка LNK2001: неразрешенный внешний символ "private: повышение статического класса :: mutex ThreadWorker :: mutex_" (? Mutex_ @ ThreadWorker @@ 0Vmutex @ импульс @@ A) 1> c: \ something \ ThreadTest \ Debug \ ThreadTest.exe: фатальная ошибка LNK1120: 1 неразрешенное внешнее

Все еще играю с ним.

Ответы [ 4 ]

6 голосов
/ 14 октября 2011

У вас есть две ошибки:

Прежде всего, как уже отмечалось, mutex_ также должен быть статическим:

private:
    static boost::mutex mutex_;

и, конечно, объявить его где-нибудь (в .cppфайл желательно!):

boost::mutex ThreadWorker::mutex_{};

Теперь, почему компилятор не жалуется?Ну, потому что вы на самом деле не создаете блокировку с аргументом mutex_ здесь:

boost::mutex::scoped_lock(mutex_);

На самом деле это не вызовет нужный вам конструктор, но создаст (локальный) объект mutex_, которыйтипа scoped_lock и создается конструктором по умолчанию.Следовательно, нет проблем с компилятором.Вы должны изменить его на что-то вроде следующего:

boost::mutex::scoped_lock l{mutex_};

Теперь компилятор должен начать жаловаться на mutex_

3 голосов
/ 14 октября 2011

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

Возможно, вы также хотели сделать mutex_ статичным?

Редактировать: Если я сделаю мьютекс статическим и удаляю статический из переменной i, то, похоже, он будет работать так, как я полагаю, вы это имели в виду. Кажется, что-то вроде этого происходит: каждый поток немедленно входит в цикл и не блокируется друг от друга из-за того, что мьютекс не является статичным. К тому времени, когда они все выводят на консоль (я не могу вспомнить, есть ли взаимное исключение при записи в cout), и я получаю приращение, все они видят статическое значение i как 30 и выход.

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

Редактировать 3: Причина, по которой он компилируется, заключается в том, что ваш scoped_lock является временным, который, кажется, лишает компилятор того факта, что mutex_ должен быть статическим. Попробуйте вместо этого следующий код:

#include <iostream>
#include "boost\thread\mutex.hpp"
#include "boost\thread\thread.hpp"

class ThreadWorker
{
public:
    ThreadWorker() {}
    virtual ~ThreadWorker() {}

    static void FirstCount(int threadId)
    {
        // Created object f here rather than temprary
        boost::mutex::scoped_lock f(mutex_);
        int i = 0; // Not static

        for(i = 1; i <= 30; i++)
        {
            std::cout << i << ": Hi from thread:  " << threadId << std::endl;
        }

    }

private:
    static boost::mutex mutex_; // Static
};

// Storage for static
boost::mutex ThreadWorker::mutex_;

int main(int argc, char* argv[])
{
    boost::thread thread1(&ThreadWorker::FirstCount, 1);
    boost::thread thread2(&ThreadWorker::FirstCount, 2);
    boost::thread thread3(&ThreadWorker::FirstCount, 3);

    thread1.join();
    thread2.join();
    thread3.join();

    std::string input;
    std::cout << "Press <enter> to finish...\n";
    std::getline( std::cin, input );
    return 0;
}
0 голосов
/ 14 октября 2011

Изменил мой код на:

ThreadWorker.h:

#pragma once
#include "boost\thread\mutex.hpp"
#include <iostream>

class ThreadWorker
{ 
public:
    ThreadWorker();
    virtual ~ThreadWorker();

    static void FirstCount(int threadId);

private:
    static boost::mutex mutex_;
};

ThreadWorker.cpp:

#include "stdafx.h"
#include "ThreadWorker.h"

boost::mutex ThreadWorker::mutex_;

ThreadWorker::ThreadWorker()
{
}

ThreadWorker::~ThreadWorker()
{
}

void ThreadWorker::FirstCount(int threadId)
{
    boost::mutex::scoped_lock xyz(mutex_);
    static int i = 0;

    for(i = 1; i <= 30; i++)
    {
        std::cout << i << ": Hi from thread:  " << threadId << std::endl;
    }

}

ThreadTest.cpp:

// ThreadTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "boost\thread\thread.hpp"
#include "ThreadWorker.h"

int _tmain(int argc, _TCHAR* argv[])
{
    boost::thread thread1(&ThreadWorker::FirstCount, 1);
    boost::thread thread2(&ThreadWorker::FirstCount, 2);
    boost::thread thread3(&ThreadWorker::FirstCount, 3);

    thread1.join();
    thread2.join();
    thread3.join();

    std::string input;
    std::cout << "Press <enter> to finish...\n";
    std::getline( std::cin, input );
    return 0;
}

Я сделал следующие изменения: 1. разделил заголовок и файл cpp (изначально я делал это только для того, чтобы сделать свой пост более компактным) 2. присвоил переменной scoped_lock идентификатор и 3. сделал мьютекс статичным.

Теперь он работает как положено, печатая 30 строк из каждого потока последовательно. Что до сих пор сбивает меня с толку, так это то, почему код, скомпилированный ранее (так как tinman также смог скомпилировать мой оригинальный код).

0 голосов
/ 14 октября 2011

Этот код также компилируется с тем же компилятором?

Вы видите проблему с этим кодом?Попробуйте определить проблему, не компилируя ее.

class C {
public:
    static int f () {
        return i;
    }

    int i;
};

int main() {
    return C::f();
}

ОБНОВЛЕНИЕ: Я только что прочитал ваше обновление.

class C {
public:
    static int f () {
        return i;
    }

    static int i;
};

int C::i = whatever;

int main() {
    return C::f();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...