2

I have 3 classes: Meeting, Project and Agenda.

  • A Project contains all sort of information + a list of meetings.
  • The Agenda contains a list of upcoming Meetings.
  • A Meeting contains some data + a list of Projects that were discussed there.

The Agenda checks for upcoming meetings. When it finds one, it calls its Meeting::alarm() method, which in turn displays data it gets from the list of projects this meeting refers to.

Meetings can be referenced in a project without being scheduled in the Agenda, but it doesn't really make sense to have a reference to a meeting in the agenda if it is not contained in a project.

Dependency between the classes

Because the Agenda can be parsed in a thread while the main thread deletes a project, I made both Agenda and Project use shared pointers on Meetings, so that the parsing thread doesn't find a dangling pointer.

In the destructor of Project, I ask Agenda to check the meetings related to this project to clean up those who don't have any other related project.

Here is my problem:
What kind of data structure should the Meeting::parentProjects member be?
If a Meeting gets called by the Agenda while its Project is being deleted, and parentProjects is a simple raw pointers container, I might have a dangling here. But I can't use a shared_ptr to Project either, since that would make a cyclic dependency... I feel like it is unnecessarily complicated.

How could I refactor this? Note: I have to keep the 2 threads though.

1

The way you are asking this question seems to imply that you expect the answer has to be in data structure. I'm not sure that it is.

The key problem is that you are wanting to modify and access the data at the same time, and have realised that attempting to access partially modified data is not good.

There are several strategies that you can do with this.

  1. In an environment where all actions on data are quick, and there is a low volume of changes you could use a Mutex (or if you want, light weight semaphores) and force the second action to block
    until the first action had completed.

  2. If these actions can take a noticeable time to occur. (e.g. 1/2 a second or more) then I would be tempted to create an action queue, and to have a your current threads place tasks on the queue, and have a third thread that performed these actions in sequence, calling a callback on the task to notify the original thread it was completed.

In simple terms, the major problem you have is the concurrent data access, rather than the data structure, so you need to solve it by managing the access, rather than by a pure data structure approach.

0

Although I share Ptolemy's concerns about the design, there is also a straightforward answer.

Meeting::parentProjects should be a weak_ptr. This does require that the Project lifetime is controlled by shared_ptr in the first place.

If a Meeting gets called by the Agenda while its Project is being deleted ...

let's break this down. Either:

  1. Meeting is called, while parent Project is still alive (shared_ptr has nonzero refcount)

    • calling weak_ptr::lock yields a shared_ptr which keeps the parent Project alive for the duration of this call
    • when the current call ends the shared_ptr implementing the temporary lock goes out of scope

    or

  2. Meeting is called after parent Project has been destroyed (shared_ptr has zero refcount)

    • calling weak_ptr::lock yields an empty shared_ptr: you can test for this and decide how to handle it

So, the Meeting will never keep its Project alive except while it's using it, and the Project cannot be deleted while the Meeting is using it.

  • I didn't know about this feature of weak_ptr. I will use it as a last resort but for now I'm trying to reorganize things as @Ptolemy suggests. – adanselm Sep 6 '13 at 18:50
  • I always thought of cycle-breaking as the primary motivation for weak_ptr, tbh. – Useless Sep 13 '13 at 8:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.