0

I need your help with wxWidgets. I have 2 threads (1 wxTimer and 1 wxThread), I need communicate between this 2 threads. I have a class that contains methods to read/write variable in this class. (Share Memory with this object)

My problem is: I instanciate with "new" this class in one thread but I don't know that necessary in second thread. Because if instanciate too, adress of variable are differents and I need communicate so I need even value in variable :/

I know about need wxSemaphore to prevent error when to access same time.

Thanks you for your help !

EDIT: My code

So, I need make a link with my code. Thanks you for all ;)

It's my declaration for my wxTimer in my class: EvtFramePrincipal (IHM)

In .h

EvtFramePrincipal( wxWindow* parent );
#include <wx/timer.h>
wxTimer m_timer;

in .cpp -Constructor EvtFramePrincipal

EvtFramePrincipal::EvtFramePrincipal( wxWindow* parent )
:
FramePrincipal( parent ),m_timer(this)
{   
Connect(wxID_ANY,wxEVT_TIMER,wxTimerEventHandler(EvtFramePrincipal::OnTimer),NULL,this);
    m_timer.Start(250);
}

So I call OnTimer method every 250ms with this line.

For my second thread start from EvtFramePrincipal (IHM):

in .h EvtFramePrincipal

#include "../Client.h"
Client *ClientIdle;

in .cpp EvtFramePrincipal

ClientIdle= new Client();
ClientIdle->Run();

In .h Client (Thread)

class Client: public wxThread
public:
    Client();
    virtual void *Entry();
    virtual void OnExit();

In .cpp Client (Thread)

Client::Client() : wxThread()
{
}

So here, no probleme, thread are ok ? Now I need that this class that use like a messenger between my 2 threads.

#ifndef PARTAGE_H
#define PARTAGE_H
#include "wx/string.h"
#include <iostream>
using std::cout;
using std::endl;


class Partage
{
    public:
        Partage();
        virtual ~Partage();
        bool Return_Capteur_Aval()
        { return Etat_Capteur_Aval; }
        bool Return_Capteur_Amont()
        { return Etat_Capteur_Amont; }
        bool Return_Etat_Barriere()
        { return Etat_Barriere; }
        bool Return_Ouverture()
        { return Demande_Ouverture; }
        bool Return_Fermeture()
        { return Demande_Fermeture; }
        bool Return_Appel()
        { return Appel_Gardien; }
        void Set_Ouverture(bool Etat)
        { Demande_Ouverture=Etat; }
        void Set_Fermeture(bool Etat)
        { Demande_Fermeture=Etat; }
        void Set_Capteur_Aval(bool Etat)
        { Etat_Capteur_Aval=Etat; }
        void Set_Capteur_Amont(bool Etat)
        { Etat_Capteur_Amont=Etat; }
        void Set_Barriere(bool Etat)
        { Etat_Barriere=Etat; }
        void Set_Appel(bool Etat)
        { Appel_Gardien=Etat; }
        void Set_Code(wxString valeur_code)
        { Code=valeur_code; }
        void Set_Badge(wxString numero_badge)
        { Badge=numero_badge; }
        void Set_Message(wxString message)
        {
            Message_Affiche=wxT("");
            Message_Affiche=message;
        }
        wxString Get_Message()
        {
            return Message_Affiche;
        }
        wxString Get_Code()
        { return Code; }
        wxString Get_Badge()
        { return Badge; }
    protected:
    private:
        bool Etat_Capteur_Aval;
        bool Etat_Capteur_Amont;
        bool Etat_Barriere;
        bool Demande_Ouverture;
        bool Demande_Fermeture;
        bool Appel_Gardien;
        wxString Code;
        wxString Badge;
        wxString Message_Affiche;
};

#endif // PARTAGE_H

So in my EvtFramePrincipal(wxTimer), I make a new for this class. But in other thread (wxThread), what I need to do to communicate ?

If difficult to understand so sorry :/

Flubox
  • 1
  • 1

2 Answers2

0

Then main thread should create first the shared variable. After it, you can create both threads and pass them a pointer to the shared variable.

So, both of them, know how interact with the shared variable. You need to implement a mutex or wxSemaphore in the methods of the shared variable.

Ivan
  • 1
-1

You can use a singleton to get access to a central object.

Alternatively, create the central object before creating the threads and pass the reference to the central object to threads.

Use a mutex in the central object to prevent simultaneous access.

Creating one central object on each thread is not an option.

EDIT 1: Adding more details and examples

Let's start with some assumptions. The OP indicated that

I have 2 threads (1 wxTimer and 1 wxThread)

To tell the truth, I know very little of the wxWidgets framework, but there's always the documentation. So I can see that:

  1. wxTimer provides a Timer that will execute the wxTimer::Notify() method when the timer expires. The documentation doesn't say anything about thread-execution (although there's a note A timer can only be used from the main thread which I'm not sure how to understand). I can guess that we should expect the Notify method will be executed in some event-loop or timer-loop thread or threads.
  2. wxThread provides a model for Thread execution, that runs the wxThread::Entry() method. Running a wxThread object will actually create a thread that runs the Entry method.

So your problem is that you need same object to be accessible in both wxTimer::Notify() and wxThread::Entry() methods.

This object:

It's not one variable but a lot of that store in one class

e.g.

struct SharedData {
  // NOTE: This is very simplistic.
  // since the information here will be modified/read by
  // multiple threads, it should be protected by one or more
  // mutexes
  // so probably a class with getter/setters will be better suited
  // so that access with mutexes can be enforced within the class.
  SharedData():var2(0) { }
  std::string var1;
  int var2;
};

of which you have somewhere an instance of that:

std::shared_ptr<SharedData> myData=std::make_shared<SharedData>();

or perhaps in pointer form or perhaps as a local variable or object attribute

Option 1: a shared reference

You're not really using wxTimer or wxThread, but classes that inherit from them (at least the wxThread::Entry() is pure virtual. In the case of wxTimer you could change the owner to a different wxEvtHandler that will receive the event, but you still need to provide an implementation.

So you can have

class MyTimer: public wxTimer {
public:
   void Notify()  {
       // Your code goes here
       // but it can access data through the local reference
   }

   void setData(const std::shared_ptr<SharedData> &data) {
       mLocalReference=data
   }

private:
   std::shared_ptr<SharedData> mLocalReferece
};

That will need to be set:

MyTimer timer;
timer.setData(myData);
timer.StartOnece(10000); // wake me up in 10 secs.

Similarly for the Thread

class MyThread: public wxThread {
public:
   void Entry()  {
       // Your code goes here
       // but it can access data through the local reference
   }

   void setData(const std::shared_ptr<SharedData> &data) {
       mLocalReference=data
   }

private:
   std::shared_ptr<SharedData> mLocalReferece
};

That will need to be set:

MyThread *thread=new MyThread();
thread->setData(myData);
thread->Run(); // threads starts running.

Option2 Using a singleton.

Sometimes you cannot modify MyThread or MyTimer... or it is too difficult to route the reference to myData to the thread or timer instances... or you're just too lazy or too busy to bother (beware of your technical debt!!!)

We can tweak the SharedData into:

struct SharedData {
  std::string var1;
  int var2;

  static SharedData *instance() {
      // NOTE that some mutexes are needed here
      // to prevent the case where first initialization
      // is executed simultaneously from different threads
      // allocating two objects, one of them leaked.
      if(!sInstance) {
          sInstance=new SharedData();
      }
      return sInstance
  }
private:
  SharedData():var2(0) { } // Note we've made the constructor private
  static SharedData *sInstance=0;
};

This object (because it only allows the creation of a single object) can be accessed from either MyTimer::Notify() or MyThread::Entry() with

SharedData::instance()->var1;

Interlude: why Singletons are evil

(or why the easy solution might bite you in the future).

My main reasons are:

  1. There's one and only one instance... and you might think that you only need one now, but who knows what the future will hold, you've taken an easy solution for a coding problem that has far reaching consequences architecturally and that might be difficult to revert.
  2. It will not allow doing dependency injection (because the actual class is used in the accessing the object).

Still, I don't think is something to completely avoid. It has its uses, it can solve your problem and it might save your day.

Option 3. Some middle ground.

You could still organize your data around a central repository with methods to access different instances (or different implementations) of the data.

This central repository can be a singleton (it is really is central, common and unique), but is not the shared data, but what is used to retrieve the shared data, e.g. identified by some ID (that might be easier to share between the threads using option 1)

Something like:

CentralRepository::instance()->getDataById(sharedId)->var1;

EDIT 2: Comments after OP posted (more) code ;)

It seems that your object EvtFramePrincipal will execute both the timer call back and it will contain the ClientIdle pointer to a Client object (the thread)... I'd do:

  1. Make the Client class contain a Portage attribute (a pointer or a smart pointer).
  2. Make the EvtFramePrincipal contain a Portage attribute (a pointer or smart pointer). I guess this will have the lifecycle of the whole application, so the Portage object can share that lifecycle too.
  3. Add Mutexes locking to all methods setting and getting in the Portage attribute, since it can be accessed from multiple threads.
  4. After the Client object is instantiated set the reference to the Portage object that the EvtFramePrincipal contains.
  5. Client can access Portage because we've set its reference when it was created. When the Entry method is run in its thread it will be able to access it.
  6. EvtFramePrincipal can access the Portage (because it is one of its attributes), so the event handler for the timer event will be able to access it.
Community
  • 1
  • 1
jsantander
  • 4,972
  • 16
  • 27
  • Advising the singleton here is a bad idea. A singleton has multiple drawbacks and sould be used only if you need global access AND instance unicity at the same time. Here, the op needs neither... – Jean-Bernard Jansen Jun 10 '14 at 15:01
  • @JBJansen, well, it is *one* possibility... and it is one of the two possibilities I offered. I usually frown upon singletons, but depending on the circumstances it might be an option. Either a singleton or a reference obtained from a central point (which is indirectly a singleton with other name) – jsantander Jun 10 '14 at 15:24
  • I don't understand singleton's method :( It's good idea for my software ? If yes, can you explain me this method ? :) – Flubox Jun 10 '14 at 18:59
  • @JBJansen I've added more details in my answer, including why singletons can be a bad choice, but you still might want to use them. – jsantander Jun 11 '14 at 09:43
  • @jsantander I have adding my code, can you make a link with it, really thanks you :) – Flubox Jun 11 '14 at 16:40
  • @Flubox... added some notes relating my answer to your code. Hope this helps. – jsantander Jun 11 '14 at 16:57