Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Вернуть значение функции из потока (boost)


Автор: correy 10.10.2013, 12:05
Здравствуйте, уже второй день бьюсь над темой. Может быть кто поможет.
У меня есть функция: ComputeSum(vector <wstring> files, int begin, int end), которая проходит вектор от begin до end, подсчитывая определенную сумму. Мне нужно, чтобы каждый из двух потоков пробегал свою часть вектора и возвращал свою сумму, каждую из которых я потом сложу и получу профит! smile

Кто-нибудь поможет?smile

Автор: azesmcar 10.10.2013, 12:22
используй http://www.boost.org/doc/libs/1_54_0/doc/html/thread/future.html

Автор: correy 10.10.2013, 12:24
Именно с этим и требуется помощь smile 

Автор: correy 10.10.2013, 12:42
Немного разобрался, получается следующее: 

boost::future <int> s1,s2;
s1 = boost::async(boost::bind(&::ComputeSum,files, begin1, end1));
int sum1 = s1.get();
s2 = boost::async(boost::bind(&::ComputeSum,files, begin2, end2));
int sum2 = s2.get();

Но в данном случае потоки работают последовательно. Или я ошибаюсь? И если я не прав, то как реализовать параллельное выполнение?

Автор: azesmcar 10.10.2013, 12:49
пример на C++11, но в boost он не должен сильно отличаться.
Код

#include <iostream>
#include <vector>
#include <future>
#include <numeric>

int calculate(
    std::vector<int>::iterator begin,
    std::vector<int>::iterator end)
{
    return std::accumulate(begin, end, 0, std::plus<int>());
}

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    std::vector<int>::iterator middle = v.begin() + v.size() / 2;

    std::future<int> result1 = std::async(calculate, v.begin(), middle);
    std::future<int> result2 = std::async(calculate, middle, v.end());

    std::cout << result1.get() + result2.get() << std::endl;
}


Добавлено через 1 минуту и 23 секунды
Цитата(correy @  10.10.2013,  12:42 Найти цитируемый пост)
Но в данном случае потоки работают последовательно. Или я ошибаюсь?

Нет, все верно.
Надо сперва создавать потоки а потом вызывать get(), так-как он блокирует вызов до завершения потока.

Автор: correy 10.10.2013, 12:55
Спасибо большое за пример!

Т.е. так потоки уже будут работать параллельно?
Код

s1 = boost::async(boost::bind(&::ComputeSum,files, begin1, end1));
s2 = boost::async(boost::bind(&::ComputeSum,files, begin2, end2));
            
wcout << L"sum = " << s1.get()+s2.get();


Автор: azesmcar 10.10.2013, 13:00
Цитата(correy @  10.10.2013,  12:55 Найти цитируемый пост)
Т.е. так потоки уже будут работать параллельно?

Верно. Вызор get() заблокирует выполнение основного потока до завершения дочерних, но сами дочерние потоки будут работать. А основной будет спать, пока те оба не завершат свою работу и не вернут результат подсчета.

Автор: correy 10.10.2013, 13:03
Цитата

Верно. Вызор get() заблокирует выполнение основного потока до завершения дочерних, но сами дочерние потоки будут работать. А основной будет спать, пока те оба не завершат свою работу и не вернут результат подсчета. 


Спасибо большое. И еще последний вопрос остался: мне в задании необходимо после каждой итерации суммирования усыплять поток на 1 секунду. Когда я запускаю свою программу, то иногда она просто зависает и не выводит результат. Это как-то может быть связано с усыплением потоков?

Грубо говоря, сейчас все работает через раз smile

Автор: correy 10.10.2013, 13:44
Возможно проблема с зависанием возникает, когда оба потока хотят одновременно вывести на экран? Если да, то как корректно организовать работу с мьютексами? Я попробовал так, но получилось не очень smile

Код

if (!wcin.fail())
        {
                
            m.lock();
            wcout << files[begin].data() << L": " << num << endl;                
            sum = sum + num;
            m.unlock();    
        }

Автор: bsa 10.10.2013, 14:15
correy, никогда не сталкивался с проблемой конкурентного вывода на консоль. Максимум, данные идут в разнобой, но ничего не виснет.
Повисания могут происходить из-за ситуации, когда один и тот же мьютекс лочится два раза. Если такой ситуации нет, то возможна более сложная: поток1 лочит мьютекс m1, поток2 лочит мьютекс m2, поток1 пытается залочить m2 и встает в ожидании, поток2 пытается залочить m1 и тоже встает. Выйти из этой ситуации уже нельзя. Надо исправлять код.

Автор: correy 10.10.2013, 14:17
Цитата

correy, никогда не сталкивался с проблемой конкурентного вывода на консоль. Максимум, данные идут в разнобой, но ничего не виснет.


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

Добавлено через 2 минуты и 4 секунды
Вот тут код моей функции:
Код


    wstreambuf *backup = wcin.rdbuf();
    int num;
    int sum=0;
    
    for (;begin <= end; begin++)
    {
        
        wifstream file(files[begin].data());
        wcin.rdbuf(file.rdbuf());
        wcin >> num; 
        
        if (!wcin.fail())
        {
            
            wcout << files[begin].data() << L": " << num << endl;                
            sum = sum + num;            
            
        }
        
        file.close();
        wcin.rdbuf(backup);
                
        Sleep(1000);
    }
    
    return sum;


Не могу понять, в чем может быть проблема(

Автор: correy 10.10.2013, 15:56
Кажется разобрался, всем спасибо!

Автор: bsa 10.10.2013, 23:59
correy, пожалуйста, всегда пиши как решил проблему. Потому что у кого-то она тоже может возникнуть.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)