#sending and receiving events from another thread

19 messages · Page 1 of 1 (latest)

vocal tapir
#

I want to send events to the main thread from other threads by having the main thread respond to the events it receives after every iteration of its loop.
Is there a way to remove the shared pointer? I don't want to accidentally free the event data before it is used and I don't know how to free it after receiving it whilst still allowing it to use any event data I want. Also is there a way to get rid of the std::vector<int>& threadEventData = *std::any_cast<std::shared_ptr<std::vector<int>>>(threadEvent.data).get(); and std::shared_ptr<std::vector<int>> outputData = std::make_shared<std::vector<int>>(std::initializer_list<int>{1, 2, 4, 6, 7});? I tried using a std::shared_ptr<std::any>>in the event struct but that made it call the move constructor.
I feel like there's an easier way to do this..

code: https://termbin.com/uuzu

late bobcatBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

versed rose
#

You may be looking for something called "Channels"

#

It's basically a synchronized queue

lament notch
#

You do not need the std::shared_ptr. If you want to avoid copies you have to move. For example in

static inline void enqueueMainEvent(ThreadEventType type, std::any data) {
    std::lock_guard<std::mutex> queueLock(g_mainEventsMutex);

    g_mainEvents.push({type, data});
}

you copy data twice. Once in the call enqueueMainEvent(ThreadEventType::Output, outputData); and a second time in g_mainEvents.push({type, data});. To avoid this use std::move. g_mainEvents.push({type, std::move(data)}); and enqueueMainEvent(ThreadEventType::Output, std::move(outputData)); will avoid the copy (there may be more unnecessary copies I missed, you can probably find them easily with an appropriate breakpoint in Lifetime).

#

As a side note,ThreadEvent reimplements std::variant poorly. You should just use that directly.

struct QuitEvent {};
using ThreadEvent = std::variant<std::vector<int>, QuitEvent>;

If multiple events need a vector<int>, put them into different structs so they have different types so you can ask the variant which type it currently holds without ambiguity.

vocal tapir
#

That works but it calls 3 move constructors and 3 destructors. Also, how would std::variant let me know what type the event is?

lament notch
#

Move constructors are basically free. It only bends some pointers.

#

Besides the example and assuming you don't use an ancient standard, you can use

std::visit([] (auto &event) {
  if constexpr (std::is_same_v<decltype(event), QuitEvent>) {
    //handle quit event
  } else if constexpr (std::is_same_v<decltype(event), std::vector<int>>) {
    //handle vector event
  }
}, variant_event);
#

It's very unfortunate that switch (decltype(event)) does not work and that inside the if you still need event.get<QuitEvent>() if you want the data because C++ does not have type narrowing.

vocal tapir
lament notch
#

Stay away from Youtube tutorials.

#

Avoiding move constructors is absolutely insane.

vocal tapir
#

He said you get more destructor calls which could call delete which would be slower

#

I mean in general. I know moving is better than copying

lament notch
#

Well, yeah, don't just move stuff around for no reason. But here you have a reason.

#

It's much cheaper than the shared_ptr.