两个线程之间的通信C ++ UNIX

时间:2014-06-10 13:57:11

标签: c++ multithreading unix wxwidgets communication

我需要你对wxWidgets的帮助。我有2个线程(1个wxTimer和1个wxThread),我需要在这2个线程之间进行通信。我有一个类,包含在这个类中读/写变量的方法。 (与此对象共享内存)

我的问题是:我在一个线程中使用“new”这个类进行实例化,但我不知道在第二个线程中有必要。因为如果也是instanciate,变量的地址是不同的,我需要沟通所以我需要变量中的值:/

我知道需要wxSemaphore来防止错误何时访问。

感谢您的帮助!

编辑:我的代码

所以,我需要与我的代码建立链接。谢谢大家;)

这是我在班上我的wxTimer的声明: EvtFramePrincipal(IHM)

在.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);
}

所以我用这条线每250ms调用一次OnTimer方法。

我的第二个帖子从EvtFramePrincipal(IHM)开始:

in .h EvtFramePrincipal

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

in .cpp EvtFramePrincipal

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

在.h客户端(线程)

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

在.cpp客户端(线程)

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

所以在这里,没有问题,线程可以吗? 现在我需要这个类在我的2个线程之间使用信使。

#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

所以在我的EvtFramePrincipal(wxTimer)中,我为这个类创建了一个新的。但在其他线程(wxThread)中,我需要做些什么才能进行通信?

如果难以理解,那么抱歉:/

2 个答案:

答案 0 :(得分:0)

然后主线程应首先创建共享变量。之后,您可以创建两个线程并向它们传递指向共享变量的指针。

因此,他们俩都知道如何与共享变量进行交互。您需要在共享变量的方法中实现互斥锁或wxSemaphore。

答案 1 :(得分:-1)

您可以使用singleton来访问中心对象。

或者,在创建线程之前创建中心对象,并将对中心对象的引用传递给线程。

在中心对象中使用互斥锁以防止同时访问。

在每个线程上创建一个中心对象不是一种选择。

编辑1:添加更多细节和示例

让我们从一些假设开始。 OP表示

  

我有2个线程(1个wxTimer和1个wxThread)

说实话,我对wxWidgets框架知之甚少,但总是有文档。所以我可以看到:

  1. wxTimer提供了一个Timer,它将在计时器到期时执行wxTimer::Notify()方法。文档没有说明线程执行的任何内容(尽管有一个注释一个定时器只能在主线程中使用,我不知道如何理解)。我猜我们应该期望Notify方法将在某些事件循环或定时器循环线程或线程中执行。
  2. wxThread提供了一个运行wxThread::Entry()方法的线程执行模型。 运行一个wxThread对象实际上会创建一个运行Entry方法的线程。
  3. 所以你的问题是你需要在wxTimer::Notify()wxThread::Entry()方法中访问同一个对象。

    这个对象:

      

    这不是一个变量,而是一个类中的很多商店

    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;
    };
    

    你在某处有一个实例:

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

    或者可能以指针形式或可能作为局部变量或对象属性

    选项1:共享参考

    你并没有真正使用wxTimerwxThread,但是从它们继承的类(至少wxThread::Entry()是纯虚拟的。对于wxTimer你可以将所有者更改为将接收该事件的其他wxEvtHandler,但您仍需要提供实施。

    所以你可以拥有

    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
    };
    

    需要设置:

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

    类似于线程

    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
    };
    

    需要设置:

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

    选项2使用单身。

    有时你无法修改MyThread或MyTimer ......或者将对myData的引用路由到线程或计时器实例太难了......或者你太懒或太忙而无法打扰(谨防你的{ {3}} !!!)

    我们可以将SharedData调整为:

    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;
    };
    

    可以从中访问此对象(因为它只允许创建单个对象) 使用

    MyTimer::Notify()MyThread::Entry()
    SharedData::instance()->var1;
    

    插曲:为什么单身人士是邪恶的

    (或为什么简单的解决方案可能会在将来咬你)。

    我的主要原因是:

    1. 只有一个实例......你可能认为现在只需要一个实例,但是谁知道未来会怎样,你已经为编码问题采取了一个简单的解决方案,这个问题在架构上具有深远的影响。这可能很难恢复。
    2. 它不允许进行依赖注入(因为实际的类用于访问对象)。
    3. 不过,我认为不能完全避免。它有它的用途,它可以解决你的问题,它可以节省你的一天。

      选项3.一些中间地带。

      您仍然可以使用访问数据的不同实例(或不同实现)的方法围绕中央存储库组织数据。

      这个中央存储库可以是单例(它实际上是中心的,通用的和唯一的),但不是共享数据,而是用于检索共享数据的内容,例如,由某个ID标识(使用选项1可能更容易在线程之间共享)

      类似的东西:

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

      编辑2:OP发布(更多)代码后的评论;)

      似乎你的对象EvtFramePrincipal将执行定时器回调,它将包含指向Client对象(线程)的ClientIdle指针......我会这样做:

      1. 使Client类包含Portage属性(指针或智能指针)。
      2. 使EvtFramePrincipal包含Portage属性(指针或智能指针)。我想这将具有整个应用程序的生命周期,因此Portage对象也可以共享该生命周期。
      3. 将Mutexes锁定添加到所有方法设置并获取Portage属性,因为它可以从多个线程访问。
      4. 实例化Client对象后,设置对EvtFramePrincipal包含的Portage对象的引用。
      5. 客户端可以访问Portage,因为我们在创建时已设置了引用。当Entry方法在其线程中运行时,它将能够访问它。
      6. EvtFramePrincipal可以访问Portage(因为它是它的一个属性),因此timer事件的事件处理程序将能够访问它。