crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )


  Ответ в std::shared_ptr и лямбда функции
Введите ваше имя
Подтвердите код

Введите в поле код из 6 символов, отображенных в виде изображения. Если вы не можете прочитать код с изображения, нажмите на изображение для генерации нового кода.
 

Опции сообщения
 Включить смайлы?
Иконки сообщения
(Опционально)
                                
                                
  [ Без иконки ]
 


Последние 10 сообщений [ в обратном порядке ]
Iron Bug Дата 18.6.2014, 7:55
  да, он там не нужен. видимо, просто остался от правки какого-то другого кода.
lanz Дата 17.6.2014, 23:39
  А у меня вопрос по этому кусочку:
pthrd1 = new thread(thread_func,3000,pfoo,[&pfoo](const std::shared_ptr<foo> pfoo)->string { return string("Func1: ") + pfoo->say_hello(); })

Зачем здесь захватывается pfoo? Оно же и так скопируется при вызове лямбды?
Iron Bug Дата 25.10.2013, 20:26
  и ещё, кстати, про потоки и функции: может, тебе стоит посмотреть на библиотечку <future>, в частности на std::async? штука полезная. по-моему, как раз очень близко к тому, что ты пытается реализовать.
Iron Bug Дата 25.10.2013, 17:27
  именно bind ничего особенного не делает. это свойство shared_ptr - увеличивать счётчик при передаче в любую функцию. поэтому bind тут просто выступает в роли функтора, в котором есть shared_ptr. когда функтор отрабатывает и уничтожается - освобождается и shared_ptr. если бы там был обычный указатель - он бы рухнул при вызове в потоке.
а насчёт boost: я его использую, кажется, с 31-й версии (если я правильно помню). так что для меня это уже почти что десять лет практики и я привыкла его использовать везде. так как boost - не просто библиотека, а испытательный полигон стандартизации С++, то почти все разработки boost потом переходят в стандарт.

насчёт сборки с потоками:
вообще, GCC принимает опцию -pthread (не -lpthread!), которая определена как -D_REENTRANT -lpthread. либо добавь её, либо определение реентерабельных функций.

в старых компиляторах библиотеки и сорцы иногда ещё нужно было указывать в обязательно строгом порядке. попробуй указать линковку после сорца. как-то так:
g++ --std=c++11 iron_code.cpp -pthread

но обычно для простых сорцов порядок сборки не так уж важен.
alexy Дата 24.10.2013, 22:16
 
Цитата(Iron Bug @ 24.10.2013, 19:23) *
под чем собираешь? с какими опциями? иногда у конкретных версий-систем бывают разные особенности. ну и сторонние библиотеки можно по-разному собирать.

g++ . А какие сторонние библиотеки? это было только std..
Раскрывающийся текст
$uname -a
Linux winter 3.2.0-54-generic #82-Ubuntu SMP Tue Sep 10 20:09:12 UTC 2013 i686 athlon i386 GNU/Linux
$g++ --version
g++ (Ubuntu/Linaro 4.7.3-2ubuntu1~12.04) 4.7.3
Copyright (C) 2012 Free Software Foundation, Inc.
Это свободно распространяемое программное обеспечение. Условия копирования
приведены в исходных текстах. Без гарантии каких-либо качеств, включая
коммерческую ценность и применимость для каких-либо целей.


если например (это твой код из последнего поста, с потоками из std) сказать
g++ --std=c++11 -Wl,--no-as-needed -lpthread iron_code.cpp
то собиреться, а если
g++ --std=c++11 -lpthread -Wl,--no-as-needed  iron_code.cpp
то не собереться... ерунда какая-то. вот выхлоп
./a.out
terminate called after throwing an instance of 'std::system_error'
  what():  Enable multithreading to use std::thread: Operation not permitted
[1]    14982 abort (core dumped)  ./a.out




Цитата(Iron Bug @ 24.10.2013, 21:53) *
bind ничего не делает сам. существование объектов должен обеспечить программист. на этот раз не стала писать по старой привычке, через boost :), сделала всё через std. хотя я не сравнивала скорость реализаций. это ещё открытый вопрос.

ну да.. сам ничего не далет)) я про деструктор говорил. этот код ответил на вопрос :)
да, скорость не знаю.. но мне кажется std как бы родной :). хотя например upgradable мутекса там нету, а нужен..
Iron Bug Дата 24.10.2013, 20:53
 
Цитата(alexy @ 24.10.2013, 2:29) *
а std::bind я так понимаю уничтожает привязанные боъекты тогда, когда уничтожается объект, возращаенной это функцией, так?

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

вот пример передачи shared_ptr в bind, с потоками:
Раскрывающийся текст
#include <iostream>
#include <functional>
#include <thread>
#include <chrono>

using namespace std;

class foo
{
public:
    void tell_value(const int& val)
    {
        cout << "Value is " << val << endl;
    }
   foo() { cout << "foo: ctor" << endl; }
   ~foo() { cout << "foo: dtor" << endl; }
};

thread *pthrd;

void thread_func(function <void (const int&)> f, const int &arg)
{
    this_thread::sleep_for(chrono::milliseconds(1000));
    f(arg);
}

void func(const shared_ptr<foo> pfoo, const int &val)
{
   pfoo->tell_value(val);
}

void main_thread()
{
    pthrd = new thread(thread_func,bind(func,shared_ptr<foo>(new foo()),placeholders::_1),10);
    cout << "Main thread finished" << endl;
}

int main()
{
   thread main_thrd(main_thread);
   main_thrd.join();
   pthrd->join();
}


на этот раз не стала писать по старой привычке, через boost :), сделала всё через std. хотя я не сравнивала скорость реализаций. это ещё открытый вопрос.
Iron Bug Дата 24.10.2013, 18:23
 
Цитата(alexy @ 24.10.2013, 15:12) *
объект в shared_ptr уничтожается когда завершаются потоки его использующие.

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

Цитата(alexy @ 24.10.2013, 15:12) *
зы: почему-то не работал без -Wl,--no-as-needed при линковке с потоками из std.. не подключал pthread?

под чем собираешь? с какими опциями? иногда у конкретных версий-систем бывают разные особенности. ну и сторонние библиотеки можно по-разному собирать.
alexy Дата 24.10.2013, 12:12
  о, работает как надо :) спасибо
объект в shared_ptr уничтожается когда завершаются потоки его использующие.

да, класс который я использую разумеется сам потокобезопасный.. там мутексы boost::signals2 и. т.д.

зы: почему-то не работал без -Wl,--no-as-needed при линковке с потоками из std.. не подключал pthread?
Iron Bug Дата 24.10.2013, 0:31
 
Цитата(alexy @ 24.10.2013, 2:29) *
в твоем коде указатель используется прямо на месте, то есть любой умный указатель в принцепе подойтед. функция go завершит исполнение и объект уничтожится..

никто тебе не запрещает передавать объект в go() извне, а внутри передавать его дальше. я просто привела простой пример.
go() там, кстати, только для демонстрации использования this в лямбда-функциях (у тебя он зачем-то прилеплен в вызовах).

если в этот пример подставить shared_ptr, то он будет потокобезопасный и у него может быть сколько угодно копий. я просто думала, что у тебя вызовы последовательно используют объект.
Внимание! "потокобезопасность" shared_ptr - это лишь безопасность обращений к самому указателю: безопасный счётчик ссылок и вызов деструктора объекта. сам объект, на который он указывает, не защищён. и если в разных потоках происходит изменение этого объекта, то надо ставить мьютексы или ещё какие-то средства синхронизации для обращения к памяти.

В случае простой передачи данных (функции thread_func - просто заглушки в том месте, где нужно вызвать создание потока):
#include <iostream>
#include <memory>

using namespace std;

class foo
{
    // какой-то класс
public:
    ~foo() { cout << "Good bye, C++11" << endl; }  // деструктор, вызывается автоматически при удалении shared_ptr
    foo() { cout << "Hello, C++11!" << endl; }   // конструктор
    string say_hello() { return "Hello!"; }
};

void thread_func(const shared_ptr<foo> pfoo,std::function<string (const shared_ptr<foo> pfoo)>f)
{
    // здесь можно создать поток и передать в него параметры, а потом их как-то вызвать
    cout << f(pfoo) << endl;
}

int main()
{
    const shared_ptr<foo> pfoo(new foo());
    thread_func(pfoo,[&pfoo](const shared_ptr<foo> pfoo)->string { return string("Func1: ") + pfoo->say_hello(); });
    thread_func(pfoo,[&pfoo](const shared_ptr<foo> pfoo)->string { return string("Func2: ") + pfoo->say_hello(); });
    return 0;
}


Вот реализация с бустовскими потоками (проверено, это работает):
Раскрывающийся текст
#include <iostream>
#include <memory>
#include <boost/thread.hpp>

using namespace std;
using namespace boost;

class foo
{
    // какой-то класс
public:
    ~foo() { cout << "Good bye, C++11" << endl; }  // деструктор, вызывается автоматически при удалении shared_ptr
    foo() { cout << "Hello, C++11!" << endl; } // конструктор
    string say_hello() { return "Hello!"; }
};

void thread_func(int delay,const std::shared_ptr<foo> pfoo,std::function<string (const std::shared_ptr<foo> pfoo)>f)
{
    this_thread::sleep(posix_time::milliseconds(delay)); // создаём вид бурной деятельности - спим! :)
    cout << f(pfoo) << endl; // вызываем нашу лямбду с объектом
}

thread *pthrd1;
thread *pthrd2;

void main_thread()
{
    const std::shared_ptr<foo> pfoo(new foo());
    pthrd1 = new thread(thread_func,3000,pfoo,[&pfoo](const std::shared_ptr<foo> pfoo)->string { return string("Func1: ") + pfoo->say_hello(); });  // этот поток будет выполняться 3 секунды
    pthrd2 = new thread(thread_func,5000,pfoo,[&pfoo](const std::shared_ptr<foo> pfoo)->string { return string("Func2: ") + pfoo->say_hello(); });  // этот поток будет выполняться 5 секунд
}

int main()
{
    thread main_thrd(main_thread);
    main_thrd.join();
    cout << "Main thread finished!" << endl;

    pthrd1->join();
    pthrd2->join();
    return 0;
}
alexy Дата 23.10.2013, 23:29
 
Цитата(Iron Bug @ 23.10.2013, 21:39) *
если я правильно поняла твою задачу :)

не совсем...
в твоем коде указатель используется прямо на месте, то есть любой умный указатель в принцепе подойтед. функция go завершит исполнение и объект уничтожится.. я попробовал передать копии shared_ptr внути go, думал упадет, но результат был тот же - объект также уничтожался по завершении функции go.

а мне нужно чтобы эту лямюду "запостить" в поток. этот поток вызовет её уже тогда, когда функция, "запостившая" и создавшая этот объект, закончит выполнение. объект, созданный в функции оператором new должен удалиться тогда, когда завершит исполнение последняя лямбда функция (иначе крах - обратиться к удаленному объекту).
сами объекты потокобезопасные..

Цитата(Iron Bug @ 23.10.2013, 21:39) *
P.S. тут такие кренделя С++11, что можно запутаться :)

да уж.. ногу сломаешь ))


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

а std::bind я так понимаю уничтожает привязанные боъекты тогда, когад уничтожается объект, возращаенной это функцией, так?
Просмотр темы полностью (откроется в новом окне)
RSS Текстовая версия Сейчас: 28.4.2024, 22:42