crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

2 страниц V   1 2 >  
Ответить в данную темуНачать новую тему
> IPC Qt/C#/C++, Межпроцессное взаимодействие
JustOneQuestion
  опции профиля:
сообщение 28.10.2015, 13:58
Сообщение #1


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 7.5.2015
Пользователь №: 4379

Спасибо сказали: 0 раз(а)




Репутация:   0  


Здравствуйте.
Ваш форум мне однажды уже помог с Qt, сейчас вот снова возникла потребность в помощи.
Подозреваю тема не нова, но что-то сходу не нашёл ответа. Начну немного издалека, чтобы вопрос был более понятный. Просто боюсь что либо я не по канонам случайно использую слова, котоыре зарезервированы в языке, в ООП, и просто в сленге под совершенно конкретные понятия, и может вовсе не те которые я бы хотел. )
Предположим у нас на плате есть 2 микроконтроллера. Каждый их них имеет у себя вечный цикл в котором чёт делается. Время от времени, в цикле, микроконтроллеры могут впадать в спячку для снижения энергопотребления. В спячке он спит мертвым сном, ничего не опрашивая, ничего не делая, просто спит. Из спячки микроконтроллер может вывести дергание за ногу(кто-то из вне подаёт ноль или единичку на ногу). Микроконтроллер после этого просыпается и дальше чёт там делает. В нашем случае один из микроконтроллеров будет будить второго. Тоесть от второго к первому будет приходить СОБЫТИЕ для пробужения. Вот это я называю СПАТЬ ПОКА НЕ ПРИЙДЕТ КАКОЕТО "СОБЫТИЕ". (Слово событие EVENT как блин только не используют(что удивительно вполне себе законно), и иногда возникает путаница(по крайней мере у меня), я поэтому и привёл пример с микроконтроллерами). Дальше вопрос микроконтроллеров касаться уже не будет. Будет просто упоминание слова СОБЫТИЕ. Вот имено точно в таком же смысле как я сейчас описал.
Суть вопроса:
Пусть у нас на компе запущено два екзешника (2 разных процесса), более того они ещё и на разных языках написаны. При этом, они должны уметь друг другу слать СОБЫТИЯ (без данных! просто: либо есть событие либо его нет). Во время работы процессы, могут засыпать в ожидании события, чтобы пока делать нечего не грузить систему. Можно БЫЛО БЫ конечно заставить их по таймеру или в цилке опрашивать какуюто переменную в SharedMemory котору бы мог изменять второй проесс, но смысла нет грузить проц и ОС такой бредовой работой. Я написал пример как это реализовать для двух процессов на С++ и C#. Код ниже. Это две аналогичные по сути программы. Не мог ли бы вы, мне помочь с таким же ТРЕТЬИМ простым примером на Qt?
С++ вариант:
#include <windows.h>
#include <stdio.h>


int main()
{
    HANDLE MyEventWaitHandleSend;
    HANDLE MyEventWaitHandleReceive;

    MyEventWaitHandleReceive=CreateEventEx(NULL, L"myEWH1", 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
    MyEventWaitHandleSend=CreateEventEx(NULL, L"myEWH2", 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
    
    printf("Waiting event from other program....\n");
    WaitForSingleObject(MyEventWaitHandleReceive, 0xFFFFFFFF);//INFINITE
    printf("Received\n");
    SetEvent(MyEventWaitHandleSend);
    printf("Sent\n");

    CloseHandle(MyEventWaitHandleReceive);
    CloseHandle(MyEventWaitHandleSend);
    
    scanf("press Enter");
    return 0;
}


C# вариант:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace WinForm
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            EventWaitHandle MyEventWaitHandleReceive;
            EventWaitHandle MyEventWaitHandleSend;

            MyEventWaitHandleReceive = new EventWaitHandle(false, EventResetMode.AutoReset, "myEWH2");
            MyEventWaitHandleSend = new EventWaitHandle(false, EventResetMode.AutoReset, "myEWH1");
            
            MyEventWaitHandleSend.Set();
            MyEventWaitHandleReceive.WaitOne();//waiting answer
            this.label1.Text = "Ok";
            
            MyEventWaitHandleReceive.Dispose();
            MyEventWaitHandleSend.Dispose();
        }
    }
}


Спасибо за внимание.

P.s.... Слышал вроде что как-то можно через QWinEventNotifier сделать, но может и иначе как-то можно...





Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 28.10.2015, 15:37
Сообщение #2


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Дело в том, что CreateEventEx платформо зависима, а Qt использует свои событийные механизмы, которые платформо независмые!.
Потому у тебя есть два варианта, либо лезть в потроха Qt и смотреть как реализована для винды событийная модель (в данном случае QWinEventNotifier), либо переходить на использование IPC общую для Windows/Linux.

Посмотри Adding Windows event objects to a Qt event loop, там описано как сделать QWinEventNotifier на Qt.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
JustOneQuestion
  опции профиля:
сообщение 28.10.2015, 19:20
Сообщение #3


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 7.5.2015
Пользователь №: 4379

Спасибо сказали: 0 раз(а)




Репутация:   0  


Цитата(ViGOur @ 28.10.2015, 15:37) *
Дело в том, что CreateEventEx платформо зависима, а Qt использует свои событийные механизмы, которые платформо независмые!.
Потому у тебя есть два варианта, либо лезть в потроха Qt и смотреть как реализована для винды событийная модель (в данном случае QWinEventNotifier), либо переходить на использование IPC общую для Windows/Linux.

Посмотри Adding Windows event objects to a Qt event loop, там описано как сделать QWinEventNotifier на Qt.

Предполагал такой ответ.
Начну с сылки. Я её видел... я qt очень плохо понимаю. В этом примере что-то много всего. Там зачем-то ещё один поток есть, но при этом нет именного события. Как тогда вобще получить како-нить идентификатор события если имени нет?... через что его в другой процесс передавать? Какими то обходными способами? Если вам понятно что в этом примере и как реализовано, пожалуйта, пожете написать пример-аналог того ктода что я на С++ написал? Там буквально десяток строк, если действительно понимать суть.

Что касается зависимости/независимости от платформы, то собственно отчасти для этого момента я и привёл пример с микроконтроллерами. Программы должны уметь послылать друг другу события.. сигналы..(В ОБЩЕМ СУЛЧАЕ!!! я по-русски говорю! :) не надо путать с event signal и прочее). Я понимаю что реализация данного момента на разных ОС может быть разной, но она должна быть! и не важно как релизовано. Иначе это не ОС а не пойми что... Я могу любые микрокотроллеры между собой ногами соеденить, програмировать их хоть на чём, и всё равно - Они смогут друг другу события слать.
В ОС просто обязана быть встроена возможно не просто тупо сидеть и в цикле или по таймеру проверять переменную или порт или ещё что-то, а реагировать на события от железа или других программ.. Прерывания жеж всегда были есть и будут на железном уровне. Если ОС не даёт с ними работать.. то это просто "ОС ЗЛА" :)

Мне кроссплатформенность не нужна. Всё на винде будет. Поэтому я хотел бы, если можно, увидеть как можно реализовать передачу событий в другой процесс через аналог "именных событий", либо увидеть другой способ, который настоящий, кроссплотформенный, умеющий слать события в другое приложение. (И не просто прослушивать в цикле, а именно слать).
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 29.10.2015, 9:53
Сообщение #4


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Работающий пример я к сожалению набросать не смогу, так как сижу по Linux, и винды рядом нет, как и дома.
Но на пальцах постараюсь объяснить.

Разберем пример по ссылке, я его перенесу сюда с коментариями, в которых опишу что и как там происходит (и немного удалю ненужное, чтобы можно было спокойно откомпилить этот пример без плясок с бубном, тем более если не понимаешь что да как в Qt):
"wineventtestthread.h"
#ifndef WINEVENTTESTTHREAD_H
#define WINEVENTTESTTHREAD_H

#include <windows.h>
#include <QThread>

// Создаётся класс потока, который отвечает за получение Windows событий
class WinEventTestThread : public QThread
{
    Q_OBJECT
public:
    explicit WinEventTestThread(void *eventH, QObject *parent = 0);
    void run();
private:
    HANDLE eventHandle;
    bool keepRunning;
signals:

public slots:

};

#endif // WINEVENTTESTTHREAD_H
"wineventtestthread.cpp"
#include "wineventtestthread.h"
#include <QDebug>

WinEventTestThread::WinEventTestThread(HANDLE eventH, QObject *parent) :
    QThread(parent)
{
    this->eventHandle = eventH;
    this->keepRunning = false;
}

// Функция потока,
void WinEventTestThread::run()
{
    qDebug() << "Test thread ID: " << QThread::currentThreadId();
    this->keepRunning = true;

    while (this->keepRunning)
    {
        // Ждём секунду, но тут никто нам не мешает поставить в место sleep
        //   WaitForSingleObject(this->eventHandle, 0xFFFFFFFF)
        sleep(1);

        // Собственно взводим Windows событие
        if (SetEvent(this->eventHandle) == 0)
        {
            qDebug() << "Test thread: Error signaling event";
        }
        else
        {
            qDebug() << "Signaled event in thread " << QThread::currentThreadId();
        }
    }
}
"mainwindow.h"
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <windows.h>
#include <QMainWindow>
#include <QtCore/private/qwineventnotifier_p.h>
#include "wineventtestthread.h"

// GUI класс окна, его можно заменить на обычный класс производный от QObject
// с макросом Q_OBJECT, чтобы заработал механизм Qt события для этого класса
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    WinEventTestThread *thread;
    HANDLE eventHandle;
    QWinEventNotifier *notifier;
// Событийная модель Qt делится на сигналы и слоты, слоты связываются с сигналами
// и вызываются, когда приходит сигнал, с которым связан слот
private slots:
    void eventSignaled(HANDLE h);
};

#endif // MAINWINDOW_H
"mainwindow.cpp"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
     // Выводим ID текущего потока
    qDebug() << "Main thread ID: " << QThread::currentThreadId();

    // Создаем неименовынное событие, нам никто не мешает его сделать именованным и заменить эту строку на
    // this->eventHandle = CreateEventEx(NULL, L"myEWH1", 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
    this->eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);

    if (this->eventHandle == NULL)
    {
        qDebug() << "Error creating event handle.";
    }
    else
    {
        // Настраиваем события для использования в связке с Qt и её событийной моделью.
        notifier = new QWinEventNotifier(this->eventHandle);
        // Сама событийная модель Qt, этой строчкой мы говорим, что при возникновении события активизации нашего this->eventHandle
        // мы хотим, чтобы была вызвана функция eventSignaled, в которую будет передан HANDLE полученного Windows события
        connect(notifier, SIGNAL(activated(HANDLE)), SLOT(eventSignaled(HANDLE)));

        // Создаем поток и запускаем его
        thread = new WinEventTestThread(this->eventHandle);
        thread->start();
    }
}

MainWindow::~MainWindow()
{
    // Не забываем остановить поток перед удалеием
    // ...
    delete thread;
}

// Функция, которая вызывается во время возникновения Windows события
void MainWindow::eventSignaled(HANDLE h)
{
    qDebug() << "Signal received in thread " << QThread::currentThreadId();
}


По моему понятно, для чего нужен поток, чтобы основной поток не висел на WaitForSingleObject и занимался своими делами.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
JustOneQuestion
  опции профиля:
сообщение 29.10.2015, 22:52
Сообщение #5


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 7.5.2015
Пользователь №: 4379

Спасибо сказали: 0 раз(а)




Репутация:   0  


Большое спасибо, ViGOur за ваши коментарии к примеру. Помогло... хотя если честно я так и не понял что там и как работает:) Сейчас поясню.
Из ваших коментариев, стало понятно что в Qt можно подключить windows.h и ипользовать все стандартные Win API функции... Точнее НЕ ВСЕ!...но те что нужны CreateEvent, WaitForSingleObject, CloseHandle, SetEvent можно. НО! CreateEventEx например нету... почему..?
Вроде всё работает хорошо. пример своего кода аналога на Qt я выложил ниже. Надо ещё потестить на скорость работы C++ варианта и Qt. Я для С# C++ сравнивал уже. Туда-сюда отправить событие + (мелкие затраты на дежуржые вещи в коде типа инкриментов счётчика цикла и проч) занимало 5мкс. Разброс от 3 до 8 примерно. максимум на 5, распределение не семитричное. Посмотрю как на Qt, будет ли разница... вроде не должна...(Мне просто интересно стало насколько быстро этот механизм работает...и насколько стабильно.. офф инфы не нашёл, решил проверить как смог сам).
А вот с примером вашим я если честно так и не понял... где там мэин...вобще?! ))) В примере там что, по циклу шлём сами себе чтоли?...Вобщем мне неловко как-то что я смысл программы не могу понять даже после ваших коментариев... Но главный вопрос не в этом... зачем вабще нужен QWinEventNotifier?!?! Он вроде к делу не имеет ни какого отношения... так зачем оно вобще нам?!
Вобщем, вот мой код(работает, проверил):
Приложение создавал типа "консольное", дальше всё вроде по умолчанию.
Для тестирования нужно запустить с примемр С++ что я выложил в первом посте.
#include <stdio.h> //Для printf
#include <conio.h> //Для getch
#include <windows.h>

//int main(int argc, char *argv[])
int main()
{
    HANDLE MyEventWaitHandleSend;
    HANDLE MyEventWaitHandleReceive;

    MyEventWaitHandleReceive=CreateEvent(NULL,FALSE, FALSE, L"myEWH2");
    MyEventWaitHandleSend=CreateEvent(NULL,FALSE, FALSE, L"myEWH1");
    //QCoreApplication a(argc, argv);
    printf("Press key to send event.\n");
    //return a.exec();
    getch();
    SetEvent(MyEventWaitHandleSend);
    printf("Sent.\n");
    printf("Waiting answer....\n");
    WaitForSingleObject(MyEventWaitHandleReceive, 0xFFFFFFFF);//INFINITE
    printf("Received.\n");
    printf("Press key to quit");
    CloseHandle(MyEventWaitHandleReceive);
    CloseHandle(MyEventWaitHandleSend);
   return 0;
}


p.s. прри создании консольного приложения засовывется строка
QCoreApplication a(argc, argv);
Я когда мышь навёл, увидел в подсказке что это якобы какойто бесконечный цикл... "сильно удивился"... скрестил пальцы в надежде что если я это сотру и попробую по старинке сам орагнизовать вечный цилк, то у меня хоть чтонить да зарабоатет... Даже побоялся читать про это...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 30.10.2015, 10:13
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(JustOneQuestion @ 30.10.2015, 0:52) *
Я когда мышь навёл, увидел в подсказке что это якобы какойто бесконечный цикл...
нет, это не бесконечный цикл. Это инициализация всяких внутренних потрахов Qt, бесконечный цикл будет тут:
a.exec();
цикл обработки сообщений. он закончится только когда будет вызван слот QCoreApplication::quit().

чаще всего (но не всегда) для консольного приложения (QCoreApplication) не требуется цикл обработки событий (QCoreApplication::exec()), однако создавать объект QCoreApplication следует (подробности в его документации).

Для GUI-приложения всегда требуется создавать и объект QGuiApplication (наследник QCoreApplication) и запускать цикл обработки событий (QGuiApplication::exec()) иначе приложение просто завершится не успев нарисовать себя на экране.

Сообщение отредактировал Litkevich Yuriy - 30.10.2015, 13:35
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ViGOur
  опции профиля:
сообщение 30.10.2015, 10:31
Сообщение #7


Мастер
******

Группа: Модератор
Сообщений: 3296
Регистрация: 9.10.2007
Из: Москва
Пользователь №: 4

Спасибо сказали: 231 раз(а)




Репутация:   40  


Тот пример, что ты набросал ничем не отличается от обычного виндового c WinApi, если хочешь Qt использовать, нужно делать так, как я описал выше, добавив свой main.cpp в котором запускается CMainWindow, такого хватит:
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CMainWindow w;
    w.show();

    return a.exec();
}


QWinEventNotifier нужен, как я писал выше, для `связывания ` Qt событий, с Windows событиями, чтобы при возникновении Windows события срабатывал Qt слот, в примере выше это MainWindow::eventSignaled.
Что такое событийная модель Qt прочитай по ссылке: Сигналы и слоты. Описание на русском.

К тому же WinApi часть примера тебе нужно переработать под себя, чтобы не посылались события самому себе. ;)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
JustOneQuestion
  опции профиля:
сообщение 30.10.2015, 12:39
Сообщение #8


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 7.5.2015
Пользователь №: 4379

Спасибо сказали: 0 раз(а)




Репутация:   0  


Спасибо, про QWinEventNotifier вроде понял. Получается что к IPC оно не имет прямого отношения, а используется только для преобразования внешнего события во внутренние. Это альтернатива связки Второй поток+WaitForSingleObject, так? В конструкторе форм в C# помимо кнопок текстбоксов и прочего графического UI, на форму можно кидать SerialPort и Timer, которые будут так же генерировать события, как и все остальные контролы. QWinEventNotifier позволяет преобразовать внешнее событие, в событие которое может обрабатываться в форме... ну точнее в программе...через сигнал и слоты...Удобно вроде кажеться... по крайней мере можно придумать задачи где это действительно удобно и логично. Хотя, WaitForSingleObject нужен бывает для синхронизации потоков или процессов. И в таком случае нет смысла использовать QWinEventNotifier, а лучше как раз WaitForSingleObject .

Я ещё вот что хотел спросить. Есть ли в макОС и линуксе аналог "именных событий" для IPC? SharedMemory думаю везде обязано быть, а что с событиями? Ну и как продолжение вопроса, есть ли действительно кроссплатформенный подход для отправки событий между процессами?

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
JustOneQuestion
  опции профиля:
сообщение 30.10.2015, 23:20
Сообщение #9


Студент
*

Группа: Новичок
Сообщений: 13
Регистрация: 7.5.2015
Пользователь №: 4379

Спасибо сказали: 0 раз(а)




Репутация:   0  


Что-то грустно как-то с приерами от Qt, особенно консольных приложений... Тут есть вобще аналог msdn? не просто описание функций класса, а чтобы ещё и с примерами...
Подскажите пожалуйста:
1. Как получить хэндл консольного приложения, ... чтобы потом QWinEventNotifier использовать.
2. Можно ли слот вне класса завести?.. в ссылке что вы мне посоветовали, было написано что слот это "функция-член" всмысле член класса? а это обязательно? Может можно просто под мэйном ещё одну функцию описать, потом как-то дать понять всем и вся что это слот. После чего через коннект связать этот слоат с событием от QWinEventNotifier и радоваться простому и понятному примеру? :)
Очень хочу протестить на скорость "Пример-аналог" но уже с использование слотов и QWinEventNotifier.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 31.10.2015, 13:54
Сообщение #10


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


Цитата(JustOneQuestion @ 30.10.2015, 14:39) *
Я ещё вот что хотел спросить. Есть ли в макОС и линуксе аналог "именных событий" для IPC? SharedMemory думаю везде обязано быть, а что с событиями? Ну и как продолжение вопроса, есть ли действительно кроссплатформенный подход для отправки событий между процессами?

если хочешь именованные события, то в Linux аналогом будет fifo (named pipe) (пример использования fifo). есть ещё сокеты. насчёт макоси не знаю, но наверняка там это есть, ибо они юникс-совместимые.

помимо Qt кроссплатформенные реализации IPC на С++ (для основных, наиболее распространённых систем) включают в себя такие библиотеки как boost (в частности, boost::interprocess), ACE (пример реализации IPC)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

2 страниц V   1 2 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.4.2024, 2:13