I use ESP-32 and need to pass std::shared_ptr using FreeRTOS queue. However, it loose one link. I think that this is source of a problem:
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
extern "C" {
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
}
class testClass {
public:
testClass() {
std::cout << "Class is constructed" << std::endl;
};
virtual ~testClass() {
std::cout << "Class is destructed" << std::endl;
};
};
struct container {
std::shared_ptr<testClass> field;
};
extern "C" void app_main(void) {
auto queue = xQueueCreate(1, sizeof(container));
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p); // 1
{
container c;
c.field = p;
PRINT_USE_COUNT(p); // 2
xQueueSendToBack(queue, &c, 0);
PRINT_USE_COUNT(p); // 2
}
PRINT_USE_COUNT(p); // 1 (Ooops!)
{
container c;
assert(xQueueReceive(queue, &c, 0) == pdTRUE);
PRINT_USE_COUNT(c.field); // 1
}
// Class is destructed
std::cout << "Test finished" << std::endl;
vQueueDelete(queue);
}
So there is a pointer in queue, but it isn't counted!
How can I solve this issue (and keep using FreeRTOS queue if possible)? Using std::move doesn't help.
A C-style queue of raw pointers will only works for C++ shared_ptr iff std::is_trivial<T>::value is true (mainly POD or trivially copyable object).
Since there are memcpy and other plain C operation manipulating memory the reference count will not be handled properly (because it is C-code behind the scene and it does not call destructor among other thing) and you could end up with a memory leak.
There is no easy way to circumvent this, but the best way is to manage the memory yourself.
See this question also : Shared pointers and queues in FreeRTOS
I managed to transform unique pointer into a raw format which could be sent via a message queue.
See here: https://codereview.stackexchange.com/questions/241886/using-unique-ptr-in-freertos.
Please note I posted it in code review because I am not sure whether there are really no memory leaks or this can be implemented much more cleanly.
I will test whether I can actually use this for the IPC in our project.
I don't always agree that developing something from scratch is best option. Using something that is well tested might be best option in most occasions even-though it could require some tweaking for making it fit to your needs.
With the queue you can pass a dynamically created instance of your container. It is very rare, if it is at all, to use a queue for sending data from one task to same task, as the example above. I don't like pretty much working with dynamic allocations in embedded CPUs, the overhead can sometimes impact performance too much.
Here below is a working PoC where, instead of a raw copy, a pointer to a new container instance is passed. In this approach it is the responsibility of the receiving task to release the instance to avoid memory leaks.
extern "C" {
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
}
#include <iostream>
#include <memory>
#define PRINT_USE_COUNT(p) std::cout << "Use count: " << p.use_count() << std::endl;
class testClass {
public:
testClass() {
std::cout << "testClass constructed" << std::endl;
}
~testClass() {
std::cout << "testClass destructed" << std::endl;
}
};
class myContainer {
public:
myContainer(std::shared_ptr<testClass> p) {
_p = p;
std::cout << "myContainer constructed" << std::endl;
}
~myContainer() {
std::cout << "myContainer destructed" << std::endl;
}
std::shared_ptr<testClass>& p() {
return _p;
}
private:
std::shared_ptr<testClass> _p;
};
extern "C" void app_main(void) {
std::cout << "Start of test, creating the shared_ptr..." << std::endl;
auto p = std::make_shared<testClass>();
PRINT_USE_COUNT(p);
std::cout << "Creating one container..." << std::endl;
myContainer c(p);
PRINT_USE_COUNT(p);
std::cout << "Creating the queue..." << std::endl;
auto q = xQueueCreate(1, sizeof(myContainer*));
std::cout << "Sending a dynamically created item to the queue..."
<< std::endl;
myContainer *cp = new myContainer(p);
xQueueSendToBack(q, &cp, 0);
PRINT_USE_COUNT(p);
{
myContainer *pc;
xQueueReceive(q, &pc, 0);
PRINT_USE_COUNT(p);
std::cout << "Use count of pc->p() " << pc->p().use_count()
<< std::endl;
std::cout << "Freeing the dynamically created item..." << std::endl;
delete pc;
PRINT_USE_COUNT(p);
}
std::cout << "end of test" << std::endl;
}
Here's the program's output:
Start of test, creating the shared_ptr...
testClass constructed
Use count: 1
Creating one container...
myContainer constructed
Use count: 2
Creating the queue...
Sending a dynamically created item to the queue...
myContainer constructed
Use count: 3
Use count: 3
Use count of pc->p() 3
Freeing the dynamically created item...
myContainer destructed
Use count: 2
end of test
myContainer destructed
testClass destructed
Related
How can a vector of objects and a single object be iterated over as-if they were the same range, without any copying or moving, in range-v3?
One possibility is to cast the single value to a std::array<Object, 1> and then concatenate this array with the vector of objects via range::views::concat:
Improvised solution
#include <array>
#include <iostream>
#include <range/v3/view/concat.hpp>
struct Object {
int value = 0;
Object() { std::cout << "Default " << value << "\n"; }
Object( int value) : value(value) { std::cout << "Value " << value << "\n"; }
Object(Object const& object) : value(object.value) { std::cout << "Copy " << value << "\n"; }
Object(Object && object) : value(std::move(object.value)) { std::cout << "Move " << value << "\n"; }
};
int main() {
// Prints "Value 0"
std::array<Object, 1> objects {0};
// Prints "Value 1"
Object object {1};
for(Object const& object : ranges::views::concat(objects, *reinterpret_cast<std::array<Object, 1>*>(&object))) {
// Prints "0 1"
std::cout << object.value << " ";
}
return 0;
}
I don't know if the cast is safe. Assuming it is, developers are at risk of having to spend time to verify this. Hence this improvised solution is wanting.
Question: Is there an elegant solution for concatenating a view and a single value without copying or moving data?
I am aware of range::views::single but this causes object to be copied once and moved thrice when used in place of reinterpret_cast in the improvised solution.
I am using boost's message queue to write a basic class with just two char arrays, but the data is not being received in the second process is empty, even though get_num_msg() returns 1 before the read and returns 0 after reading. For debugging purposes I also tried writing and reading from the same process, and that worked fine. I am using the shared pointer because earlier while just reading and writing integers, it would not read the integer at the receiver unless it was declared as shared ptr.
AccessQueue
class AccessQueue {
public:
char name[64];
char action[64];
AccessQueue(char name[64], char action[64]) {
strcpy(this->name, name);
strcpy(this->action, action);
}
AccessQueue() {}
};
sending function
// std::shared_ptr<AccessQueue> p1;
this->p1.reset(new AccessQueue("asd", "vsq"));
try {
this->mq->send(&p1, sizeof(p1), 0);
} catch(boost::interprocess::interprocess_exception & ex) {
std::cout << ex.what() << std::endl;
}
receiving function
std::cout << this->mq->get_num_msg() << "\t" << this->mq->get_max_msg_size() << "\t" << this->mq->get_max_msg() << std::endl;
AccessQueue * a;
unsigned int priority;
boost::interprocess::message_queue::size_type recvd_size;
try {
this->mq->try_receive(&a, sizeof(AccessQueue), recvd_size, priority);
} catch(boost::interprocess::interprocess_exception & ex) {
std::cout << ex.what() << std::endl;
}
std::cout << this->mq->get_num_msg() << "\t" << this->mq->get_max_msg_size() << "\t" << this->mq->get_max_msg() << std::endl;
std::cout << "It clearly maybe works " << a->action << "\t" << a->name << std::endl;
output at receiver's end:
1 128 20
0 128 20
Looks like p1 (in the sending function) is a smart pointer (like std::unique_ptr or std::shared_ptr). In that case
this->mq->send(&p1, sizeof(p1), 0);
is obviously wrong, because it puts the pointer object on the queue, instead of the data structure. Use
this->mq->send(*p1, sizeof(*p1), 0);
Or, indeed, don't use dynamic allocation in the first place:
AccessQueue packet("asd", "vsq");
mq.send(&packet, sizeof(packet), 0);
Uhoh there's more
On the receiving side, there's a similar problem:
AccessQueue * a;
// ..
mq.try_receive(&a, sizeof(AccessQueue), ...);
That receives INTO the pointer, not the object. You don't even have an object, because a (the pointer) is never initialized. Here the fix is syntactically simple:
AccessQueue a;
No more pointers. Now, a is an object and &a is the address of that object.
Note how the original was UB because you read sizeof(AccessQueue) bytes into a pointer. However the pointer is only 8 bytes and the struct is 128 bytes. Ooops!
Simplified Working Demo
This works:
Live On Wandbox¹
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <iomanip>
namespace bip = boost::interprocess;
using MQ = bip::message_queue;
template<size_t N>
static inline void safe_copy(std::array<char, N>& dst, std::string_view src) {
std::copy_n(src.data(), std::min(src.size(), N), dst.data());
dst.back() = 0; // make sure of NUL termination
}
struct AccessQueue {
std::array<char, 64> name{0};
std::array<char, 64> action{0};
AccessQueue(std::string_view n = "", std::string_view a = "") {
safe_copy(name, n);
safe_copy(action, a);
}
};
static_assert(std::is_standard_layout_v<AccessQueue>);
struct X {
void send() {
AccessQueue packet("asd", "vsq");
try {
mq.send(&packet, sizeof(packet), 0);
} catch(std::exception const & ex) {
std::cout << ex.what() << std::endl;
}
}
AccessQueue receive() {
AccessQueue retval;
report();
try {
unsigned int priority;
MQ::size_type recvd_size;
mq.try_receive(&retval, sizeof(AccessQueue), recvd_size, priority);
} catch(std::exception const & ex) {
std::cout << ex.what() << std::endl;
}
report();
return retval;
}
void report() {
std::cout << mq.get_num_msg() << "\t" << mq.get_max_msg_size() << "\t" << mq.get_max_msg() << std::endl;
}
MQ mq { bip::open_or_create, "somequeue", 10, sizeof(AccessQueue) };
};
int main() {
X tryit;
tryit.send();
auto const& [name, action] = tryit.receive();
std::cout << std::quoted(name.data()) << " " << std::quoted(action.data()) << std::endl;
}
Prints
1 128 10
0 128 10
"asd" "vsq"
Note
using std::array over C arrays gives you copy semantics by default
guard the POD-ness of AccessQueue
make sure the members are initialized
make sure the copies are safe
make sure the copies are NUL-terminated always
Don't use new or delete. Why should C++ programmers minimize use of 'new'?
make sure your receive buffer size matches the max_msg_size (boost interprocess message_queue and fork)
¹ shared emmory is prohibited on Wandbox :(
When I read the document in cppreference here
https://en.cppreference.com/w/cpp/memory/shared_ptr#Example
I am wondering what the possible value of the first lp.use_count() printed out is? I marked it with "<<<<<" in output content.
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
struct Base
{
Base() { std::cout << " Base::Base()\n"; }
// Note: non-virtual destructor is OK here
~Base() { std::cout << " Base::~Base()\n"; }
};
struct Derived: public Base
{
Derived() { std::cout << " Derived::Derived()\n"; }
~Derived() { std::cout << " Derived::~Derived()\n"; }
};
void thr(std::shared_ptr<Base> p)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::shared_ptr<Base> lp = p; // thread-safe, even though the
// shared use_count is incremented
{
static std::mutex io_mutex;
std::lock_guard<std::mutex> lk(io_mutex);
std::cout << "local pointer in a thread:\n"
<< " lp.get() = " << lp.get()
<< ", lp.use_count() = " << lp.use_count() << '\n';
}
}
int main()
{
std::shared_ptr<Base> p = std::make_shared<Derived>();
std::cout << "Created a shared Derived (as a pointer to Base)\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
std::thread t1(thr, p), t2(thr, p), t3(thr, p);
p.reset(); // release ownership from main
std::cout << "Shared ownership between 3 threads and released\n"
<< "ownership from main:\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
t1.join(); t2.join(); t3.join();
std::cout << "All threads completed, the last one deleted Derived\n";
}
Possible output:
Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
p.get() = 0x2299b30, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
p.get() = 0, p.use_count() = 0
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 5 <<<<<<<< HERE <<<<<<
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 3
local pointer in a thread:
lp.get() = 0x2299b30, lp.use_count() = 2
Derived::~Derived()
Base::~Base()
All threads completed, the last one deleted Derived
#user2452809 's answer is very appreciated, which pointed out an important feature of use_count().
Supposing use_count() would return an accurate count, what would be the answer?
I wouldn't rely on that value anyway.
In multithreaded environment, the value returned by use_count is approximate (typical implementations use a memory_order_relaxed load)
Check the reference for more information: https://en.cppreference.com/w/cpp/memory/shared_ptr/use_count
I think it could be one value of {4,5,6}. Am I right?
Q: Why larger than 3?
A: When printing, at least one thr function is invoked. Including the reference in main function. the use_count should be 3. But it's not possible when one thread sleep for one second and other two hadnot been constructed.
On the other hand, if there're two threads finished, the last thread would have a use_count 3. But it would not be the first line because of the thread mutex in printing scope.
Q: Why less than 7?
A: Because during the sleep in subthread, the main thread will run p.reset(). One second is a quite long time to CPU.
Now I need to detect whether my class is created as a stack/global/thread_local variable, for example:
class Foo {
public:
Foo() {
if(im_on_stack) {
std::cout << "I'm on stack" << std::endl;
} else if(im_in_global) {
std::cout << "I'm in global" << std::endl;
} else if(im_a_thread_local) {
std::cout << "I'm a thread_local" << std::endl;
} else {
std::cout << "I'm on ohters location" << std::endl;
}
}
};
class Bar {
Foo mFoo;
};
Foo gFoo;
thread_local Foo tFoo;
int main() {
Foo lFoo;
}
and the out put should be:
I'm on ohters location
I'm in global
I'm a thread_local
I'm on stack
This there any way in C++ I can do this?
Edit:
why I'm doing this:
I'm writing a garbage collection library, and I got a class, let's call it gc_ptr, I need to know if this gc_ptr is a gc root (which is create on the location I mentioned) or not (which is a member of another class)
Edit2:
According to the concept of gc root, which is a reference which is not on a heap, I should probably asked in this way: can I detect if my class is create on the heap? But I think on heap or on stack make this question no difference.
Short answer: No. Not with standard C++. There may be compiler or OS specific solutions, but nothing portable.
I guess you could make a heuristic to detect stack allocated objects by detecting in their constructor whether their address is close to a stack allocated variable. Assuming that the stack and the heap have completely different memory addresses it should work. Completely undefined behaviour though according to the standard. e.g.:
#include <iostream>
#include <memory>
struct A
{
A()
{
int test = 0; // test is on the stack
auto distance = reinterpret_cast<char*>(this) - reinterpret_cast<char*>(&test);
isStack = std::abs(distance) < 1024; // completely arbitrary magic number, will need to experiment
}
bool isStack;
};
int main()
{
std::cout << "stack: " << A().isStack << "\n";
std::cout << "stack: " << std::make_unique<A>()->isStack << "\n";
}
I don't think you could expand this technique to thread local variables. You'd also need to take care in copy constructors and assignment operators to handle copying from a stack to a heap object and vice versa.
This is not part of the spec, so no.
If you told us on what system/os you are working, maybe we can assist - some systems may provide the stack address and size - usually this is available in embedded devices as part of the compiler output (the address), and as input (the size) as part of the environment/project configuration.
What I wrote in my comment:
Can be done to some extent: Assuming, you need it only for a certain kind of classes: You have to overload new (or wrap dynamic construction in a static create). You have to derive all considered classes from a base class with a specific constructor. To pass info from new to the constructor is a bit tricky. In our case, we used a global set where new remembered pointers to created instances and the corresponding constructor looked into it to determine whether creation was done by new. That was sufficient for us. (About the other topics - no idea...)
A demo:
#include <iostream>
#include <set>
class Object {
private:
static thread_local std::set<void*> pNewSet;
bool _isNewed;
public:
Object();
Object(const Object&) = delete;
const Object& operator=(const Object&) = delete;
~Object() = default;
static void* operator new(size_t size);
bool isNewed() const { return _isNewed; }
private:
static std::set<void*>& getNewPtrs()
{
static thread_local std::set<void*> pNewSet;
return pNewSet;
}
};
void* Object::operator new(size_t size)
{
std::set<void*> &pNewSet = getNewPtrs();
void *p = ::operator new(size);
if (p) pNewSet.insert(p);
return p;
}
Object::Object(): _isNewed(false)
{
std::set<void*> &pNewSet = getNewPtrs();
std::set<void*>::iterator iter = pNewSet.find((void*)this);
if (iter != pNewSet.end()) {
_isNewed = true;
pNewSet.erase(iter);
}
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
// a global static instance
static Object o;
int main()
{
DEBUG(std::cout << o.isNewed() << '\n');
// a static instance (local scope)
DEBUG(static Object o1);
DEBUG(std::cout << o1.isNewed() << '\n');
// a local instance
DEBUG(Object o2);
DEBUG(std::cout << o2.isNewed() << '\n');
// as members
DEBUG(struct Composed { Object o1, o2; } comp);
DEBUG(std::cout << comp.o1.isNewed() << ' ' << comp.o2.isNewed() << '\n');
// created with new
DEBUG(Object *pO = new Object());
DEBUG(std::cout << pO->isNewed() << '\n');
DEBUG(delete pO);
// created as members in an object created with new
DEBUG(Composed *pComp = new Composed());
DEBUG(std::cout << pComp->o1.isNewed() << ' ' << pComp->o2.isNewed() << '\n');
DEBUG(delete pComp);
}
Output:
std::cout << o.isNewed() << '\n';
0
static Object o1;
std::cout << o1.isNewed() << '\n';
0
Object o2;
std::cout << o2.isNewed() << '\n';
0
struct Composed { Object o1, o2; } comp;
std::cout << comp.o1.isNewed() << ' ' << comp.o2.isNewed() << '\n';
0 0
Object *pO = new Object();
std::cout << pO->isNewed() << '\n';
1
delete pO;
Composed *pComp = new Composed();
std::cout << pComp->o1.isNewed() << ' ' << pComp->o2.isNewed() << '\n';
0 0
delete pComp;
Live Demo on Compiler Explorer
Notes:
The copy constructor and assignment operator of Object are deleted intenionally.
Derived classes may provide a copy constructor but it has to call Object::Object().
The sample doesn't consider other flavors of new (e.g. operator new[] or the align variants since C++17). That should be done in productive code.
No, but you can prevent creation of objects on heap/stack.
To prevent creation on stack make the destructor private/protected:
class heap_only
{
public:
void release() const { delete this; }
protected:
~heap_only() {}
};
struct heap_only_deleter
{
void operator()( heap_only* p ) { p->release(); }
};
using up_heap_only = std::unique_ptr<heap_only, heap_only_deleter>;
//...
heap_only ho; // fails
heap_only* pho = new heap_only();
pho->release();
up_heap_only up{ new heap_only() };
To prevent creation on heap make the new operators private/protected:
class stack_only
{
protected:
static void* operator new( std::size_t );
static void* operator new[]( std::size_t );
};
//...
stack_only* pso = new stack_only(); // fails
stack_only so;
Regarding your edits, and just for fun:
void* pstart;
bool is_on_stack( void* p )
{
int end;
return pstart >= p && p > &end;
}
int globalint;
int main()
{
//
int start;
pstart = &start;
//
int stackint;
std::cout << std::boolalpha
<< is_on_stack( &globalint ) << std::endl
<< is_on_stack( &stackint ) << std::endl
<< is_on_stack( new int );
//...
}
I have set up this example:
class UsefulClass {
public:
int id;
const bool operator< (const UsefulClass &other) const {
return this->id > other.id;
}
UsefulClass(int _id): id(_id) {
std::cout << "constructing " << id << std::endl;
}
~UsefulClass() {
std::cout << "destructing " << id << std::endl;
}
};
std::set<UsefulClass> set;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
set.insert(object_1);
set.insert(std::move(object_2));
std::cout << "create end" << std::endl;
}
int main() {
create();
std::cout << "main end" << std::endl;
}
I am expecting that the objects get destructed once when set gets deleted at the end of the program. But the objects get deleted twice:
constructing 1
constructing 2
create end
destructing 2
destructing 1
main end
destructing 1
destructing 2
Why is set.insert creating a copy here?
The objects in the set are different from the objects local to create(). The ones in the set are constructed using a copy constructor and move constructor, not the constructor UsefulClass(int), so you don't see their construction. The local objects get destroyed when the function create() returns, and then the objects in the set get destroyed at global cleanup after main ends.
object_1 and object_2 are created on stack and will be destroyed once the create() function ends. They need to be copied in the memory managed by set's allocator.
If you redefine the copy constructor, to trace its execution, you'll notice it is called at both inserts.
Rule of 3 applies to your case, if you print from dtor and want meaningful trace you should instrument copy (and maybe move) ctor also.
If you do that output will make sense and things should be properly paired.
Because your objects get copied on insertion into the set. Hence, when the create() function returns, the two local objects are destroyed. After main ends, the two copies that are in the set are destroyed, leading to the second pair of messages.
To illustrate whatever everybody has said before me, just create this simple example (it uses a new copy constructor for the set to use and uses a global variable to generate different ids each time a constructor is executed ---it's been tested, so you can put it in a file and compile):
#include <iostream>
#include <string>
#include <set>
using namespace std;
class UsefulClass {
static int instance;
public:
int id;
int i;
const bool operator<(const UsefulClass &other) const {
return id < other.id;
}
UsefulClass(int i){
id = instance++;
this->i = i;
cout << "constructing "
<< id
<< ":"
<< this->i
<< endl;
}
UsefulClass(const UsefulClass& other) {
id = instance++;
i = other.i;
cout << "constructing "
<< id
<< ":"
<< i
<< endl;
}
~UsefulClass(){
cout << "destructing "
<< id
<< ":"
<< i
<< endl;
}
};
int UsefulClass::instance = 0;
std::set<UsefulClass> myset;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
myset.insert(object_1);
/* please, explain what you mean with std::move, or which move
* have you used for the next statement. All i have is
* std::move(... ) for strings, but you have not defined
* string UsefulClass::operator string();
*/
myset.insert(/*std::move*/(object_2));
cout << "create end"
<< endl;
}
int main() {
create();
cout << "main end"
<< std::endl;
}
so you'll get a different instance id whenever you create a UsefulClass object and you'll see that when inserting into the set they are being copied as new instances. You'll see when each object is being created and when they are being deleted.
$ pru
constructing 0:1
constructing 1:2
constructing 2:1
constructing 3:2
create end
destructing 1:2
destructing 0:1
main end
destructing 2:1
destructing 3:2