crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> Неожиданное поведение программы при работе в Windows 2000, некорректная отработка....
AD
  опции профиля:
сообщение 18.6.2009, 12:45
Сообщение #1


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

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

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




Репутация:   17  


Вот вкладка работы в автоматическом режиме
[attachment=675:picture1.JPG]

Задается количество вращений по каждой из плоскостей и запускается выполнение (выполнение происходит в отдельных потоках). Отдельно вращение в вертикальной проекции - доп. поток VerticalRotation, отдельное - в горизонтальной - доп. поток HorizontalRotation. В Windows XP все отрабатывает корректно. Параллельно вращается прожектор в обеих плоскостях, есть отсчет счетчиков - все нормально. В Windows 2000 вращение дает делать только поочередно, отсчет счетчиков происходит только по окончании выполнения цикла.

Как можно поправить этот глюк?

Сообщение отредактировал AD - 18.6.2009, 13:14
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 18.6.2009, 13:31
Сообщение #2


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

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

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




Репутация:   17  


Система такая:
Вкладка унаследована от QWidget. НА ней размещены элементы, как показано на рисунке.
После открытия порта, становятся доступны кнопки "Start Vertical", "Start Horizontal" При нажатии на каждую из кнопок запускается соответствующий поток выполнения вращения. Вот некоторое описание использующихся классов:
VerticalProjection
/// Класс потока - вращение вокруг горизонтальной оси заданное количество раз
class VerticalRotation: public QThread
{
    Q_OBJECT

private:
    INFO_TO_EXTERN_DEVICE inf_to_ed_packet;        ///< пакет данных внешнему устройству в режиме авто управления
    INFO_FROM_EXTERN_DEVICE inf_from_ed_packet;    ///< пакет данных от внешнего устройства в режиме авто управления
    const int MAXBYTES;                            ///< константа максимального количества байт
    int number_rotate;                            ///< количество вращений
    ImitatorTSL* imitTsl;                        ///< указатель на класс главного окна
    bool terminated;                            ///< флаг сигнализации о том, что функцию run надо прервать
    bool checked_pause;                            ///< флаг нажатия на кнопку паузы

private:
    void readAngleElevation(int& geted_angle_elev, double limit);
    void cycleRotate();

protected:
    virtual void run();

signals:
    void valueDecrement(int);
    void timeout(int);

private slots:
    void terminateCycle(int index) { terminated = true; }

public:
    VerticalRotation(QObject *parent);
    ~VerticalRotation() {}
    void tsl(ImitatorTSL* im) { imitTsl = im; }
    ImitatorTSL* tsl() const { return imitTsl; }
    int rotNumber() const { return number_rotate; }
    void setRotNumber(const int num) { number_rotate = num; }
    INFO_TO_EXTERN_DEVICE autoControl();
    void fromExternalDevice(INFO_FROM_EXTERN_DEVICE& mp);
    void setToEDInfo(const INFO_TO_EXTERN_DEVICE& ed) { inf_to_ed_packet = ed; }
    void setFromEDInfo(const INFO_FROM_EXTERN_DEVICE& ed) { inf_from_ed_packet = ed; }
    INFO_TO_EXTERN_DEVICE toEDInfo() { return inf_to_ed_packet; }
    INFO_FROM_EXTERN_DEVICE fromEDInfo() { return inf_from_ed_packet; }
    void setTerminate(bool bf) { terminated = bf; }
    bool isTeminated() const { return terminated; }
    void setChecked(bool value) { checked_pause = value; }
};



HorizontalProjection
/// Класс потока - вращение вокруг вертикальной оси заданное количество раз
class HorizontalRotation: public QThread
{
    Q_OBJECT

private:
    INFO_TO_EXTERN_DEVICE inf_to_ed_packet;        ///< пакет данных внешнему устройству в режиме авто управления
    INFO_FROM_EXTERN_DEVICE inf_from_ed_packet;    ///< пакет данных от внешнего устройства в режиме авто управления
    const int MAXBYTES;                            ///< константа максимального количества байт
    int number_rotate;                            ///< количество вращений
    ImitatorTSL* imitTsl;                        ///< указатель на класс главного окна
    bool terminated;                            ///< флаг сигнализации о том, что функцию run надо прервать
    bool checked_pause;                            ///< флаг нажатия на кнопку паузы

private:
    void readAzimuth(int& geted_azimuth, double limit);
    void cycleRotate();

protected:
    virtual void run();

signals:
    void valueDecrement(int);
    void timeout(int);

private slots:
    void terminateCycle(int index) { terminated = true; }

public:
    HorizontalRotation(QObject *parent);
    ~HorizontalRotation() {}
    void tsl(ImitatorTSL* im) { imitTsl = im; }
    ImitatorTSL* tsl() const { return imitTsl; }
    int rotNumber() const { return number_rotate; }
    void setRotNumber(const int num) { number_rotate = num; }
    INFO_TO_EXTERN_DEVICE autoControl();
    void fromExternalDevice(INFO_FROM_EXTERN_DEVICE& mp);
    void setToEDInfo(const INFO_TO_EXTERN_DEVICE& ed) { inf_to_ed_packet = ed; }
    void setFromEDInfo(const INFO_FROM_EXTERN_DEVICE& ed) { inf_from_ed_packet = ed; }
    INFO_TO_EXTERN_DEVICE toEDInfo() { return inf_to_ed_packet; }
    INFO_FROM_EXTERN_DEVICE fromEDInfo() { return inf_from_ed_packet; }
    void setTerminate(bool bf) { terminated = bf; }
    bool isTeminated() const { return terminated; }
    void setChecked(bool value) { checked_pause = value; }
};


Вот класс, где есть слоты выполнения нажатия на кнопки и сами потоки:
Раскрывающийся текст
/// Класс отображения параметров внешних устройств управления в автоматическом режиме
class AutoControl: public QWidget, public AutoControlClass
{
    Q_OBJECT

private:
    INFO_TO_EXTERN_DEVICE inf_to_ed_packet;        ///< пакет данных внешнему устройству в режиме авто управления
    const int MAXBYTES;                            ///< константа максимального количества байт
    ImitatorTSL* imitTsl;                        ///< указатель на класс главного окна
    HorizontalRotation* horizontal;                ///< вращение в горизонтальной плоскости (дополнительный поток)
    VerticalRotation* vertical;                    ///< вращение в вертикальной плоскости (дополнительный поток)
    time_t started_time_horiz;                    ///< начальное время при перемещении по горизонтали
    time_t started_time_vert;                    ///< начальное время при перемещении по вертикали
    time_t mean_time_horiz;                        ///< среднее время при перемещении по горизонтали
    time_t mean_time_vert;                        ///< среднее время при перемещении по вертикали
    bool is_working_horizontal;                    ///< флаг, сигнализирующий о работе в горизонтальной проекции
    bool is_working_vertical;                    ///< флаг, сигнализирующий о работе в вертикальной проекции

private:
    void readAzimuth(int& geted_azimuth, double limit);
    void readAngleElevation(int& geted_angle_elev, double limit);

private slots:
    void startHorizontalCycles();
    void startVerticalCycles();
    void pauseHorizontalCycles();
    void pauseVerticalCycles();
    void horizCountChange(int value);
    void vertCountChange(int value);

public:
    AutoControl(QWidget *parent = 0);
    ~AutoControl();
    INFO_TO_EXTERN_DEVICE autoControl();
    void fromExternalDevice(INFO_FROM_EXTERN_DEVICE& mp);
    void checkPacket();
    void tsl(ImitatorTSL* im)
    { imitTsl = im; if(horizontal) horizontal -> tsl(im); if(vertical) vertical -> tsl(im); }
    ImitatorTSL* tsl() const { return imitTsl; }
};


Функции запуска потоков:
/// Запуск циклического перемещения по горизонтальной плоскости
void AutoControl::startHorizontalCycles()
{
    horizontal -> setRotNumber(spinHorizCycles -> value());
    mean_time_horiz = 0;
    time(&started_time_horiz);
    horizontal -> start();
    horizTimer -> setText(QString("00"));
    if(spinHorizCycles -> value() > 1) btnPauseHorizontal -> setEnabled(true);
}

/// Запуск циклического перемещения по вертикальной плоскости
void AutoControl::startVerticalCycles()
{
    vertical -> setRotNumber(spinVertCycles -> value());
    mean_time_vert = 0;
    time(&started_time_vert);
    vertical -> start();
    vertTimer -> setText(QString("00"));
    if(spinVertCycles -> value() > 1) btnPauseVertical -> setEnabled(true);
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 19.6.2009, 8:59
Сообщение #3


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

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

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




Репутация:   17  


Что-то не получается. Под XP работает нормально, а под Windows 2000 некорректно. Вот код, где идет синхронизация информации, принимаемой от потоков:
// Внутри класса
QSemaphore sem_resource;

// в конструкторе
sem_resource(2)

/// Возвращение пакета с данными от внешнего устройства в режиме автоматического управления
INFO_TO_EXTERN_DEVICE AutoControl::autoControl()
{
    sem_resource.acquire(1);
    INFO_TO_EXTERN_DEVICE horiz = horizontal -> autoControl();
    inf_to_ed_packet.high_azim = horiz.high_azim;
    inf_to_ed_packet.low_azim = horiz.low_azim;
    sem_resource.release(1);

    sem_resource.acquire(1);
    INFO_TO_EXTERN_DEVICE vert = vertical -> autoControl();
    inf_to_ed_packet.high_angle_elev = vert.high_angle_elev;
    inf_to_ed_packet.low_angle_elev = vert.low_angle_elev;
    sem_resource.release(1);

    BYTE sum = 0;
    BYTE* ptr = (BYTE*) (&inf_to_ed_packet);
    for(register int i=0; i<(sizeof(inf_to_ed_packet) - 1); ++i) sum += ptr[i];
    inf_to_ed_packet.checksum = MAXBYTES - sum;
    return inf_to_ed_packet;
}


Сообщение отредактировал AD - 19.6.2009, 9:01
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 23.6.2009, 12:29
Сообщение #4


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

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

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




Репутация:   17  


Проблему удалось решить. Если посмотреть на код, то можно увидеть, что чтение данных от прожектора идет в каждом потоке отдельно. Было сделано предположение, что в Windows 2000 прочитанные данные распределяются между потоками не пакетами, а какими-то половинчатыми кусками принятых данных.

Для решения был создан еще один поток, куда были вынесены чтение из порта и запись в порт. Если будет интересно, то покажу получившийся код. В каком-то смысле он стал немного запутаннее, а в каком-то лучше! :)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 23.6.2009, 13:51
Сообщение #5


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

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

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




Репутация:   17  


Думал, кому-нибудь такие вещи будут интересны.....
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 23.6.2009, 14:09
Сообщение #6


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

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

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




Репутация:   34  


Цитата(AD @ 23.6.2009, 14:51) *
Думал, кому-нибудь такие вещи будут интересны.....

Не интересно, потому, что в коде присутствуют какие-то структуры неизвестного назначения, к тому же нигде не написан сокральный смысл создания массы потоков, которые будут читать все с одного устройство. Да и вообще работа Qt со своими девайсами мало интересует. Это, как правильно, не кроссплатформенно и узконаправлено, типа сигналы с датчиков читать или работать с программатором через COM-порт. Какие-то промышленные задачи.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 6.12.2019, 8:58