Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Работа функции


Автор: Acer 4.12.2008, 22:04
Есть метод класса. Его работа заключается в выборке данных из базы и записи этих данных в определенное поле класса.
Вот код, который работает:
Код

void RModuleCore::updateData(){
    long n = 0;
    std::string q( "SELECT atm FROM atm_data WHERE id = '" );
    q += this->mid; q += "'";
    n = this->rdbc.execQuery( q );
    if ( n > 0 ){
        this->data_atm.resize( n );
        char atm[10];
        long ds = 0;
        this->rdbc.getCellValue( 1, atm, 10, &ds, 1 );
        this->data_atm[0].atm = atm;
    }
}

А вот код, который не работает:
Код

void RModuleCore::updateData(){
    long n = 0;
    std::string q( "SELECT atm FROM atm_data WHERE id = '" );
    q += this->mid; q += "'";
    n = this->rdbc.execQuery( q );
    if ( n > 0 ){
        this->data_atm.resize( n );
        char atm[10];
        long ds = 0;
        this->rdbc.getCellValue( 1, atm, 10, &ds, 1 );
        this->data_atm[0].atm = atm;
    } else {
        this->clearData();
    }
}

Подскажите, в чем проблема? Почему при добавлении 2-х строк кода в выше приведенную функцию вот эта
Код

this->rdbc.execQuery( q );

возвращает -1 ?


--------------------------------------------------------------
Код

void RModuleCore::clearData(){
    this->data_atm.clear();
    this->data_global.clear();
}

Автор: J0ker 4.12.2008, 22:30
такое может быть только в одном случае - если во втором случае перед этим вызывался любой код, который изменил состояние rdbc
приведенный вами код никакой информации не несет - из него лишь можно сделать предположение, что перед вызовом RModuleCore::updateData() был еще один вызов RModuleCore::updateData(), который в else изменил состояние rdbc, и последующий вызов привел к ошибке.

Автор: Acer 4.12.2008, 23:06
хм... вроде нигде не должно меняться состояние обьекта rdbc...
Ну вот, смотрите:
начну с main:
Код

    RModule *md;
    for ( int i = 0; i < ( int )modules.size(); i++ ){
        screen->showMessage( modules[i].key.c_str(), Qt::AlignRight | Qt::AlignCenter );
        md = new RModule( &gcfg, mw.instance(), ws );
        md->init( modules[i].key.c_str(), modules[i].value.c_str() );
        ws->addModule( md );
    }

тут из конфиг файла беру данные о модулях и создаю обьекты для каждого модуля. Затем они добавляются в ws (workspace)
Далее после инициализации модулей они живут сами по себе. А именно:
в конструкторе класса RModule:
Код

this->connect( timer, SIGNAL( timeout() ), this, SLOT( updateData() ) );

Это Qt. По истечению времени таймера запускается метод класса RModule - updateData()
RModule::updateData()
Код

void RModule::updateData(){
    if ( this->mod_core->isConnected() ){
        this->mod_core->start();
    }
}

RModuleCore::isConnected()
Код

bool RModuleCore::isConnected(){
    return this->rdbc.isConnected();
}

RODBC::isConnected()
Код

bool RODBC::isConnected(){
    char value[256];
    long value_s;
    return SQLGetConnectAttr( this->hdbc, SQL_ATTR_CONNECTION_DEAD, value, 256, &value_s ) == SQL_SUCCESS;
}

mod_core - это свойство обьекта класса RModule и является экземпляром класса RModuleCore.
RModuleCore для каждого модуля запускается в отдельном потоке. При выполнении mod_core->start(); запускается метод run:
RModuleCore::run()
Код

void RModuleCore::run(){
    this->updateData();
    emit this->endWorking();
}

После завершения работы метода this->updateData() в классе RModuleCore генерируется сигнал, который оповещает RModule о том, что нужно запустить updateDisplay();
RModuleCore::updateData()
Код

void RModuleCore::updateData(){
    long n = 0;
    std::string q( "SELECT atm FROM atm_data WHERE id = '" );
    q += this->mid; q += "'";
    n = this->rdbc.execQuery( q );
    if ( n > 0 ){
        this->data_atm.resize( n );
        char atm[10];
        long ds = 0;
        this->rdbc.getCellValue( 1, atm, 10, &ds, 1 );
        this->data_atm[0].atm = atm;
    } else {
        this->clearData();
    }
}


RModule::updateDisplay()
Код

void RModule::updateDisplay(){
    if ( this->mod_core->getDataAtm().size() == 0 ){
        this->setIconStat( this->ind_conn_db, false );
        return;
    } else {
        this->setIconStat( this->ind_conn_db, true );
    }

    QTreeWidgetItem *item = new QTreeWidgetItem;
    item->setText( 0, this->mod_core->getDataAtm().at( 0 ).atm.c_str() );
    this->atm_list->addTopLevelItem( item );

    this->windowActivate();
    this->windowFlash();
    this->playSound();
}

В методе RModule::updateDisplay() берутся данные, которые RModuleCore достал из базы:
RModuleCore::getDataAtm()
Код

std::vector<_data_atm> RModuleCore::getDataAtm(){
    return this->data_atm;
}

Данные представляют собой вектор структур(мало полей, так как программа в стадии разработки):
Код

typedef struct {
    std::string atm;
} _data_atm;

Далее, что касается класса, работающего с базой:

RODBC::execQuery
Код

long RODBC::execQuery(std::string q){
    int n = ( int )q.size();
    if ( this->exec( q, n + 1 ) ){
        this->connection = true;
        return this->getRowsCount();
    } else {
        return -1;
    }
}


RODBC::exec
Код

bool RODBC::exec(std::string q,int q_length){
    return SQLExecDirect( this->hstmt, ( UCHAR* )q.c_str(), q_length ) == SQL_SUCCESS;
}


RODBC::getRowsCount
Код

long RODBC::getRowsCount(){
    long n;
    SQLRowCount( this->hstmt, &n );
    return n;
}


RODBC::getCellValue
Код

bool RODBC::getCellValue(int idx,void *value,long v_size,long *d_size,short cm){
    RETCODE rc;
    if ( cm == 1 ){
        SQLFetch( this->hstmt );
    }
    return SQLGetData( this->hstmt, idx, SQL_C_DEFAULT, value, v_size, d_size ) == SQL_SUCCESS;
}

Автор: J0ker 4.12.2008, 23:16
ээээ
давайте вы просто дебагером пройдетесь и посмотрите все обращения к rdbc, а заодно и сверитесь с документацией по библиотеке, предоставляющий этот объект

Автор: Acer 4.12.2008, 23:22
Я сам писал эту библиотеку smile

Автор: J0ker 4.12.2008, 23:35
тем более

Автор: Acer 4.12.2008, 23:48
Еще один интересный факт:
Первый запрос проходит нормально, а второй уже возвращает -1

Автор: J0ker 5.12.2008, 00:34
это я и имел ввиду
у вас объект вероятно не детерминирован

Автор: Acer 5.12.2008, 20:52
Вобщем, проблема в том, что я еще не совсем понимаю многопоточную обработку данных....
Я заменил библиотеку для работы с базами. Но непонятно вот-что: при старте программы все модули коннектятся к базе. Но потом соединение остается только у последнего. Все, кто грузился ранее, теряют связь с базой :(

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)