Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IPC Qt/C#/C++
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Общие вопросы
JustOneQuestion
Здравствуйте.
Ваш форум мне однажды уже помог с 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
Дело в том, что CreateEventEx платформо зависима, а Qt использует свои событийные механизмы, которые платформо независмые!.
Потому у тебя есть два варианта, либо лезть в потроха Qt и смотреть как реализована для винды событийная модель (в данном случае QWinEventNotifier), либо переходить на использование IPC общую для Windows/Linux.

Посмотри Adding Windows event objects to a Qt event loop, там описано как сделать QWinEventNotifier на Qt.
JustOneQuestion
Цитата(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
Работающий пример я к сожалению набросать не смогу, так как сижу по 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
Большое спасибо, 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
Цитата(JustOneQuestion @ 30.10.2015, 0:52) *
Я когда мышь навёл, увидел в подсказке что это якобы какойто бесконечный цикл...
нет, это не бесконечный цикл. Это инициализация всяких внутренних потрахов Qt, бесконечный цикл будет тут:
a.exec();
цикл обработки сообщений. он закончится только когда будет вызван слот QCoreApplication::quit().

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

Для GUI-приложения всегда требуется создавать и объект QGuiApplication (наследник QCoreApplication) и запускать цикл обработки событий (QGuiApplication::exec()) иначе приложение просто завершится не успев нарисовать себя на экране.
ViGOur
Тот пример, что ты набросал ничем не отличается от обычного виндового 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
Спасибо, про QWinEventNotifier вроде понял. Получается что к IPC оно не имет прямого отношения, а используется только для преобразования внешнего события во внутренние. Это альтернатива связки Второй поток+WaitForSingleObject, так? В конструкторе форм в C# помимо кнопок текстбоксов и прочего графического UI, на форму можно кидать SerialPort и Timer, которые будут так же генерировать события, как и все остальные контролы. QWinEventNotifier позволяет преобразовать внешнее событие, в событие которое может обрабатываться в форме... ну точнее в программе...через сигнал и слоты...Удобно вроде кажеться... по крайней мере можно придумать задачи где это действительно удобно и логично. Хотя, WaitForSingleObject нужен бывает для синхронизации потоков или процессов. И в таком случае нет смысла использовать QWinEventNotifier, а лучше как раз WaitForSingleObject .

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

JustOneQuestion
Что-то грустно как-то с приерами от Qt, особенно консольных приложений... Тут есть вобще аналог msdn? не просто описание функций класса, а чтобы ещё и с примерами...
Подскажите пожалуйста:
1. Как получить хэндл консольного приложения, ... чтобы потом QWinEventNotifier использовать.
2. Можно ли слот вне класса завести?.. в ссылке что вы мне посоветовали, было написано что слот это "функция-член" всмысле член класса? а это обязательно? Может можно просто под мэйном ещё одну функцию описать, потом как-то дать понять всем и вся что это слот. После чего через коннект связать этот слоат с событием от QWinEventNotifier и радоваться простому и понятному примеру? :)
Очень хочу протестить на скорость "Пример-аналог" но уже с использование слотов и QWinEventNotifier.
Iron Bug
Цитата(JustOneQuestion @ 30.10.2015, 14:39) *
Я ещё вот что хотел спросить. Есть ли в макОС и линуксе аналог "именных событий" для IPC? SharedMemory думаю везде обязано быть, а что с событиями? Ну и как продолжение вопроса, есть ли действительно кроссплатформенный подход для отправки событий между процессами?

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

помимо Qt кроссплатформенные реализации IPC на С++ (для основных, наиболее распространённых систем) включают в себя такие библиотеки как boost (в частности, boost::interprocess), ACE (пример реализации IPC)
JustOneQuestion
Спасибо, Iron Bug за наводки. Но если я правильно понимаю, то это скорее примеры способов передачи данных. Подробно не разбирался, но что именные каналы что ACE работают с данными по принципу пишем-читаем. Если есть что прочитать - прочитаем.Захотели записать- запишем. Однако, как читателю узнать что пришли новые данные? Надо вроде постоянно самому проверять... или всё же нет и можно как-то подписаться на событие прихода данных. Меня интересует именно способ сообщить в другое преложение что что-то произошло. Это мне кажется вопрос который имеет отношение не столько к библиотекам и языку на котором пишеться сколько к возможностям ОС или железа. Например можно засунуть в обработчик прерываний микрокотроллера или микропроцессора ссылку на место в одном процессе, а вызывать будет другой процесс.(в случае микроконтроллера прерывание будет кто-то извне делать, как я описывал в первом посте.) Но в принципе ни что не мешает ... если железо позволяет ... и самому себе прерывание устроить, например ногуВввода для сигнала прерывания соеденить с ногой вывода. Это можно и совтовым способ сделать... если у железа есть под это регистры для управления такими перемычками. Если без железа это всё смотреть, то ОС должна эмулировать примерно тот же процесс с помощью своего великого и всемогущего (а так же непонятно как работающего) Планировщика_Задач. Перестаёт давать время на выполнение операций одного процесса, до тех пор, пока другой процесс не отправит сигнал планировщику о том чтобы тот разбудил первого. Тут дело вобщем-то не в библиотеках а в принципе, и мнме кажется он должен быть универсальным для всех систем... так или иначе. Исходя из этого, мне становится непонятно, почему же тогда CreateEventEx платформенно зависима? Принцип то должен быть универсальным... А вот реализация да.. может быть и разной.. Но ничто не мешает в библиотеке с CreateEventEx сделать дефайны при компиляции под определенную систему..Главное ж чтобы тот кто пишет код используя эти функции всегда одним способом мог пользоваться...Что под одну ОС что под другую. А как оно там реализовано это уже его не должно беспокоить, как не беспокоят его ("обычно") вопросы как тот или иной драйвер работает. Есть стандарт для каждого типа устройств, и работают уже с ним. А чтобы этот стандарт был един для всех физически разны устройств это уже забота драйвера.
Я что-то не то говорю?

И ещё одоно... помогите с примерром консольного приложения и слотов ) и чтобы без классов. Ну зачем городить класс там, где принципиально больше одного экземпляра не будет, и вобще по сути только одна функция типа паблик и переменных никаких... Можно без усложнений? ) Ну и именно консольное.. мне все эти окна с графикой тут не нужны.
ViGOur
Цитата(JustOneQuestion @ 31.10.2015, 16:56) *
И ещё одоно... помогите с примерром консольного приложения и слотов ) и чтобы без классов. Ну зачем городить класс там, где принципиально больше одного экземпляра не будет, и вобще по сути только одна функция типа паблик и переменных никаких... Можно без усложнений? ) Ну и именно консольное.. мне все эти окна с графикой тут не нужны.
Дело в том, что событийная модель построенна на классах, производных от QObject и с определенными макросами (Q_OBJECT), из этого класса Qt генерирует moc файлы, которые участвуют в проекте и реализуют механизм сигнал/слот.
С функциями такое не прокатит.
Iron Bug
Цитата(JustOneQuestion @ 31.10.2015, 18:56) *
Спасибо, Iron Bug за наводки. Но если я правильно понимаю, то это скорее примеры способов передачи данных. Подробно не разбирался, но что именные каналы что ACE работают с данными по принципу пишем-читаем. Если есть что прочитать - прочитаем.Захотели записать- запишем. Однако, как читателю узнать что пришли новые данные? Надо вроде постоянно самому проверять... или всё же нет и можно как-то подписаться на событие прихода данных. Меня интересует именно способ сообщить в другое преложение что что-то произошло. Это мне кажется вопрос который имеет отношение не столько к библиотекам и языку на котором пишеться сколько к возможностям ОС или железа.

в любой OS есть объекты синхронизации, которые поддерживаются ядром. собственно, процесс может опросить состояние объекта без блокирования, либо подписаться на изменение его состояния и спать, пока система его не разбудит. подобные операции реализованы везде и процесс может либо проверить наличие данных и сразу вернуть себе управление, либо спать до прихода некоторого события. когда процесс получил данные, он может делать с ними что угодно, в том числе дёргать какие-то колбэки. все реализации так или иначе делают именно это, просто эта работа выполняется библиотеками и может быть скрыта от конечного юзера. само собой ничего не делается. с разной степенью тормозов это реализовано в Qt и boost::interprocess. вопрос лишь в том, каковы требования по скорости и по поддерживаемым платформам. если реализация устраивает, то нет смысла городить свои велосипеды, в крупных кроссплатформенных библиотеках всё это есть.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.