@Anykei

Как правильно настроить взаимодействие от переменной объявленной в классе?

В данный момент написан абстрактный интерфейс класса:
class InstrumentInterface {
public:
	virtual ~InstrumentInterface() = default;
	virtual bool getLock() = 0;
	virtual std::string writeCommand(std::string*) = 0;
	virtual std::string readCommand() = 0;
protected:
	std::mutex interfaceControl;
};

От него определяю методы:
class InstrumentalServer : public InstrumentInterface
{
public:
	InstrumentalServer() = default;
	virtual ~InstrumentalServer();

	void initSocketServer();

	void addDevice(AbstractDevice*);

	virtual bool getLock() override;
	virtual std::string writeCommand(std::string*) override;
	virtual std::string readCommand() override;
private:
	SocketServer* sockServer;
	AbstractDevice* device;
};

Внуть класса SocketServer передаю this для возможности взаимодействия с AbstractDevice (будут еще 2 сервера и передавать AbstractDevice серверу бессмысленно, так как класс InstrumentalServer должен контролировать доступ к AbstractDevice ):
void InstrumentalServer::initSocketServer()
{
	sockServer = new SocketServer(this);
}

Внутри класса SocketServer в отдельном потоке сервера вызываю функции интерфейса:
try
{
	Interface->writeCommand(buf);
}
catch (const std::exception& ex)
{
	std::cerr << ex.what() << std::endl;
}

Насколько это правильно? Каким правильным способом я могу отдать данные в InstrumentalServer из SocketServer?
Спасибо за ответы!
  • Вопрос задан
  • 122 просмотра
Решения вопроса 1
@menkar3
Отвечу как сам понял вопрос, может быть вообще мимо.
Основная проблема - сильная связность. У вас более низкоуровневый класс SocketServer зачем-то должен знать о существовании InstrumentInterface который им владеет.
Я бы предложил передавать серверу в конструкторе "что-то", куда он сможет писать полученные данные. Простой пример - InstrumentalServer ждет, пока не поступят данные от сервера, и пишет их в девайс. Простой пример, который работает вечно - сервер просыпается раз в секунду, записывает данные и засыпает. При появление данных InstrumentalServer просыпается, пишет их в девайс, и засыпает, снова ожидая входящие данные. Классическая многопоточная задачка же. Удалил методы из интерфейса.
struct MessageQueue
{
    std::condition_variable cv;
    std::mutex messMtx;
    std::queue<std::string> serverMessages;
};

struct AbstractDevice
{
    void processData(std::string message)
    {
        std::cout << message << std::endl;
    }
};

class SocketServer
{
public:
    SocketServer(MessageQueue& mess)
        : out(mess)
    {
        std::thread t(&SocketServer::processData, this);
        t.detach();
    }

    void processData()
    {
        for (;;)
        {
            try
            {
                std::lock_guard<std::mutex> lock(out.messMtx);
                // some output data
                out.serverMessages.push("some string 1");
                out.serverMessages.push("some string 2");
                // completed this iteration
                out.cv.notify_one();
            }
            catch (const std::exception& ex)
            {
                std::cerr << ex.what() << std::endl;
            }
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

private:
    MessageQueue& out;
};

class InstrumentInterface {
public:
    virtual ~InstrumentInterface() = default;
};

class InstrumentalServer : public InstrumentInterface
{
public:
    InstrumentalServer() = default;

    void addDevice(AbstractDevice* dev) { device = dev; };

    void waitForMessages()
    {
        for (;;)
        {
            std::unique_lock<std::mutex> lock(messages.messMtx);
            // sleep until messages received
            messages.cv.wait(lock, [this]() {return !messages.serverMessages.empty(); });
            while (!messages.serverMessages.empty())
            {
                device->processData(messages.serverMessages.front());
                messages.serverMessages.pop();
            }
        }
    }

private:
    MessageQueue messages;
    std::unique_ptr<SocketServer> sockServer = std::make_unique<SocketServer>(messages);
    AbstractDevice* device;
};

int main()
{
    AbstractDevice device;
    InstrumentalServer iServer;
    iServer.addDevice(&device);
    iServer.waitForMessages();
    return 0;
}

Можно было бы сделать отдельный мьютекс для девайса, конечно, чтобы надолго мьютекс сообщений не захватывать. Тогда под мьютексом сообщений создаем пустую очередь, свопаем ее с очередью сообщений, освобождаем мьютекс сообщений, захватываем мьютекс девайса, пишем в девайс.
Я правильно понял вопрос?
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы