Связь между двумя потоками C ++ UNIX

0

Мне нужна ваша помощь с wxWidgets. У меня есть 2 потока (1 wxTimer и 1 wxThread), мне нужно установить связь между этими двумя потоками. У меня есть класс, который содержит методы чтения/записи переменных в этом классе. (Совместное использование памяти с этим объектом)

Моя проблема заключается в следующем: я инициирую "новый" этот класс в одном потоке, но я не знаю, что необходимо во втором потоке. Потому что, если instanciate тоже, адрес переменной является разным, и мне нужно общаться, поэтому мне нужно значение в переменной:/

Я знаю о необходимости wxSemaphore, чтобы предотвратить ошибку при доступе в одно и то же время.

Спасибо вам за помощь!

EDIT: Мой код

Итак, мне нужно сделать ссылку с моим кодом. Спасибо вам всем;)

Это мое объявление для моего wxTimer в моем классе: EvtFramePrincipal (IHM)

В.h

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

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

Поэтому я вызываю метод OnTimer каждые 250 мс с этой строкой.

Для моего второго потока начинаем с EvtFramePrincipal (IHM):

в.h EvtFramePrincipal

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

в.cpp EvtFramePrincipal

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

В.h Client (Thread)

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

В.cpp Client (Thread)

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), что мне нужно сделать, чтобы общаться?

Если трудно понять, так жаль:/

Теги:
multithreading
communication
wxwidgets

2 ответа

0

Затем основной поток должен создать сначала общую переменную. После этого вы можете создать оба потока и передать им указатель на общую переменную.

Итак, оба они знают, как взаимодействовать с общей переменной. Вам необходимо реализовать mutex или wxSemaphore в методах общей переменной.

  • 0
    Это не одна переменная, а множество этого хранилища в одном классе. Можете ли вы иметь пример кода для меня?
  • 0
    @Flubox Я добавил больше подробностей в своем ответе, надеюсь, они прояснят
0

Вы можете использовать синглтон, чтобы получить доступ к центральному объекту.

Кроме того, создайте центральный объект перед созданием потоков и передайте ссылку на центральный объект на потоки.

Используйте мьютекс в центральном объекте для предотвращения одновременного доступа.

Создание одного центрального объекта в каждом потоке не является вариантом.

EDIT 1: добавление более подробной информации и примеров

Начнем с некоторых предположений. ОП указала, что

У меня есть 2 потока (1 wxTimer и 1 wxThread)

Честно говоря, я очень мало знаю о структуре wxWidgets, но всегда есть документация. Поэтому я вижу, что:

  1. wxTimer предоставляет таймер, который будет выполнять метод wxTimer::Notify() когда истечет таймер. Документация ничего не говорит о выполнении потока (хотя есть примечание. Таймер может использоваться только из основного потока, который я не уверен, как понимать). Я могу догадаться, что мы должны ожидать, что метод Notify будет выполняться в потоке или потоках цикла цикла или цикла таймера.
  2. wxThread предоставляет модель для выполнения Thread, которая запускает метод wxThread::Entry(). Запуск объекта wxThread фактически создаст поток, который запускает метод Entry.

Таким образом, ваша проблема в том, что вам нужен тот же объект для доступа как в wxTimer::Notify() и в wxThread::Entry().

Этот объект:

Это не одна переменная, а большая часть этого магазина в одном классе

например

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: общая ссылка

Вы действительно не используете wxTimer или wxThread, но классы, наследующие от них (по крайней мере, 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.

Option2 Использование синглтона.

Иногда вы не можете изменять MyThread или MyTimer... или слишком сложно перенаправить ссылку на myData на поток или экземпляры таймера... или вы слишком ленивы или слишком заняты, чтобы беспокоиться (остерегайтесь вашего технического долга ! !)

Мы можем настроить 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. Некоторая средняя земля.

Вы все равно можете организовать свои данные в центральном репозитории с помощью методов доступа к различным экземплярам (или различным реализациям) данных.

Этот центральный репозиторий может быть одноточечным (он действительно является центральным, распространенным и уникальным), но не является общими данными, а используется для извлечения общих данных, например, идентифицированных с помощью некоторого идентификатора (который может быть проще распределить между потоки с использованием опции 1)

Что-то вроде:

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

EDIT 2: комментарии после опубликованного OP (более) кода;)

Кажется, что ваш объект EvtFramePrincipal выполнит как обратный вызов таймера, так и будет содержать указатель ClientIdle для объекта Client (поток)... Я бы сделал:

  1. Создайте класс Client с атрибутом Portage (указатель или интеллектуальный указатель).
  2. Сделать EvtFramePrincipal содержать атрибут Portage (указатель или интеллектуальный указатель). Я предполагаю, что это будет иметь жизненный цикл всего приложения, поэтому объект Portage может совместно использовать этот жизненный цикл.
  3. Добавьте блокировку Mutexes ко всем настройкам методов и попаданию в атрибут Portage, поскольку к ним можно получить доступ из нескольких потоков.
  4. После создания экземпляра объекта Client установите ссылку на объект Portage, который содержит EvtFramePrincipal.
  5. Клиент может получить доступ к Portage, потому что мы установили его ссылку, когда она была создана. Когда метод Entry запускается в своем потоке, он сможет получить к нему доступ.
  6. EvtFramePrincipal может получить доступ к Portage (поскольку это один из его атрибутов), поэтому обработчик события для события таймера сможет получить к нему доступ.
  • 0
    Консультирование синглтона здесь - плохая идея. Синглтон имеет несколько недостатков и может использоваться только в том случае, если вам требуется глобальный доступ и уникальность экземпляра одновременно. Здесь опера не нуждается ни в ...
  • 0
    @JBJansen, ну, это одна из возможностей ... и это одна из двух возможностей, которые я предложил. Я обычно хмуро смотрю на одиночек, но в зависимости от обстоятельств это может быть вариантом. Либо синглтон, либо ссылка, полученная из центральной точки (которая косвенно является синглтоном с другим именем)
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню