# Plugin not destructing

**URL:** <https://mworks.discourse.group/t/plugin-not-destructing/469>\
**Category:** Support\
**Created:** [February 3, 2016, 4:33pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469 "2016-02-03T16:33:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 3, 2016, 4:33pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/1 "2016-02-03T16:33:13Z")

</div>

Hi Chris,

I have recently started to write on a Plugin for a custom Teensy-IO using MWorks 0.6.

This plugin establishes a connection to the Teensy within the initialization routine and then schedules 5 executions of a sync event in order to sync Teensy and MWorks time.

I do this (within Teensy::initialize()):

```auto
    scheduler = Scheduler::instance();
    shared_ptr<Teensy> this_one = component_shared_from_this<Teensy>();
    schedule_node = scheduler->scheduleMS(std::string(FILELINE ": ") + getTag(),
                                          1, //defer first start 1ms
                                          1000, //repeat every second
                                          5,//M_REPEAT_INDEFINITELY,
                                          boost::bind(send_sync_request_, this_one),
                                          M_DEFAULT_PRIORITY,
                                          M_DEFAULT_WARN_SLOP_US,
                                          M_DEFAULT_FAIL_SLOP_US,
                                          M_MISSED_EXECUTION_DROP);

```

As a result, I get 5 executions of the send\_sync\_request function. But doing this also prevents the plugin from ever reaching the destructor. I need to reset the serial port there (which works perfectly when no scheduling takes place). What am I doing wrong? Should I clear the shared\_ptr manually and how would this look like exactly?

Thank you for your help,  
Philipp

PS: I used the Eyelink Plugin as a template. I didn’t have time to check, but it might be it will also never destruct once started… this should be checked out.

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 3, 2016, 6:17pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/2 "2016-02-03T18:17:43Z")

</div>

Hi Philipp,

Because you use a `shared_ptr` in the call to `boost::bind`, `schedule_node` owns a reference to the `Teensy` instance. If `schedule_node` is a member of the `Teensy` class, then this creates a reference cycle, which prevents the instance from being destructed.

In order to break the cycle, you need to destroy `schedule_node` outside of the `Teensy` destructor. For an I/O device, a likely place to do this is in the `stopDeviceIO` method. Add the following:

```
if (schedule_node) {
    schedule_node->cancel(); // Ensure the task is stopped
    schedule_node.reset(); // Release the ScheduleTask instance
}

```

> PS: I used the Eyelink Plugin as a template. I didn’t have time to check, but it might be it will also never destruct once started… this should be checked out.

OK, I’ll take a look.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 4, 2016, 10:39am UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/3 "2016-02-04T10:39:26Z")

</div>

Hi Chris,

thank you for your fast reply.

I can of course destroy the schedule\_node within stopDeviceIO(), but the idea was that the clock syncing starts at plugin load time and ends when the plugin is unloaded. I can live with this not being possible, but what will happen when the server attempts to unload the plugin while it is running? Will stopDeviceIO() be called automatically then or will the reference cycle then still prevent the plugin from being unloaded?

For the case of the Eyelink plugin, I think I checked within the destructor whether the device was still running and if it was, I would stop and destroy the schedule nodes like you suggested. This was working just fine, but now, if I understand you right, the destructor will not even be called if a reference cycle exists, even if this cycle would break within the destructor. Is there perhaps another function that I can use? Something like “plugin\_unload()”?

Best,  
Philipp

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 4, 2016, 3:22pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/4 "2016-02-04T15:22:34Z")

</div>

Hi Philipp,

> I can of course destroy the schedule\_node within stopDeviceIO(), but the idea was that the clock syncing starts at plugin load time and ends when the plugin is unloaded.

OK, then you probably want to use a [weak\_ptr](http://www.boost.org/doc/libs/1_60_0/libs/smart_ptr/weak_ptr.htm). In `initialize`, create `schedule_node` like this:

```
auto weak_this = boost::weak_ptr<Teensy>(component_shared_from_this<Teensy>());
auto functor = [weak_this]() {
    if (auto shared_this = weak_this.lock()) {
       send_sync_request_(shared_this);
    }
}
schedule_node = scheduler->scheduleMS(std::string(FILELINE ": ") + getTag(),
                                      1, //defer first start 1ms
                                      1000, //repeat every second
                                      M_REPEAT_INDEFINITELY,
                                      functor,
                                      M_DEFAULT_PRIORITY,
                                      M_DEFAULT_WARN_SLOP_US,
                                      M_DEFAULT_FAIL_SLOP_US,
                                      M_MISSED_EXECUTION_DROP);

```

This way, `schedule_node` does _not_ own a reference to the `Teensy` instance, so it won’t prevent its destruction. You can then put the `schedule_node` shutdown code that I shared previously in the `Teensy` destructor.

> For the case of the Eyelink plugin, I think I checked within the destructor whether the device was still running and if it was, I would stop and destroy the schedule nodes like you suggested. This was working just fine, but now, if I understand you right, the destructor will not even be called if a reference cycle exists, even if this cycle would break within the destructor.

Yes, you understand correctly. However, the EyeLink plugin works, because it does what I recommended in my previous message: It [destroys the schedule node in stopDeviceIO](https://github.com/dicarlolab-mworks/EyeLink1000/blob/master/Eyelink.cpp#L443). The [similar code in the destructor](https://github.com/dicarlolab-mworks/EyeLink1000/blob/master/Eyelink.cpp#L202) could be removed, because if the schedule node still exists, the destructor will never run.

Chris

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 4, 2016, 5:26pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/5 "2016-02-04T17:26:25Z")

</div>

Thank you Chris, this works great !!

Now, is there any disadvantage to using the weak\_ptr instead of shared\_ptr? Can something go wrong when there are two scheduler nodes working in parallel, both with weak pointers?

Thanks again for the great help!  
Philipp

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [February 5, 2016, 12:57pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/6 "2016-02-05T12:57:03Z")

</div>

Hi Philipp,

> Now, is there any disadvantage to using the weak\_ptr instead of shared\_ptr?

The only disadvantage is the added complexity of needing to ensure that the pointed-to object still exists before (and while) you use it. My example code shows the right way to do this: First attempt to create a shared\_ptr (i.e. strong reference) with the [lock](http://www.boost.org/doc/libs/1_60_0/libs/smart_ptr/weak_ptr.htm#lock) method, and if successful, hold on to the shared\_ptr for as long as you need to use the object:

```
if (auto strong_ref = weak_ref.lock()) {
    // Do work with strong_ref
    // ...
    // strong_ref goes out of scope here, and strong reference is released
}

```

> Can something go wrong when there are two scheduler nodes working in parallel, both with weak pointers?

Nothing can go wrong that can’t also go wrong using shared pointers. In both cases, if multiple threads are accessing the same object, then you need to use some synchronization mechanism (e.g. mutex locks) to prevent one thread from modifying shared data while another thread reads or writes that data.

Cheers,  
Chris

---

<div class="post-metadata">

**Author:** ![cstawarz](https://yyz1.discourse-cdn.com/flex031/user_avatar/mworks.discourse.group/cstawarz/32/3_2.png) [@cstawarz](https://mworks.discourse.group/u/cstawarz)\
**Post date:** [July 19, 2022, 10:10pm UTC](https://mworks.discourse.group/t/plugin-not-destructing/469/7 "2022-07-19T22:10:27Z")

</div>


