WedX - журнал о программировании и компьютерных науках

Использовать несколько ORB через разные потоки (многопоточное клиентское приложение с несколькими сферами) — как?

Этот вопрос связан с: Возможно ли иметь несколько объектов ORB в одном процессе?

Итак, благодаря @BrianKelly я нашел информацию об идентификаторе ORB (хотя такой информации не было во всех ORBACUS документах, которые у меня есть) и успешно создал простое приложение, которое подключается к разным CORBA серверам и успешно выполнило несколько CORBA запросов. .

Все идет нормально.

Теперь я хочу сделать это приложение многопоточным и запустить отдельный поток для подключения к разным серверам. Но ORB_init вылетает.

Вот очень короткий код, который я использую для тестирования:

#include <OB/CORBA.h>

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* run( void * );

struct config { const char* nameservice; const char* id; const char* exe; };

const bool mt = true;

int main()
{
    config cfg1 = { "NameService=corbaloc::10.102.8.15:13069/NameService", "1", "test" };
    config cfg2 = { "NameService=corbaloc::192.168.1.99:13069/NameService", "2", "test" };

    if( mt )
    {   
        pthread_t t1, t2;

        pthread_create( &t1, NULL, run, (void*)&cfg1 ); 
        pthread_create( &t2, NULL, run, (void*)&cfg2 ); 

        pthread_join( t1, NULL ); pthread_join( t2, NULL );
    }
    else
    {
        run( (void*)&cfg1 );
        run( (void*)&cfg2 );
    }

    printf( "SUCCESS!\n" );
    return 0;
}

void* run( void* arg )
{
    pthread_mutex_lock( &mutex );

    int argc = 2; char* argv[3];

    config* cfg = (config*)arg;
    argv[0] = (char*)cfg->exe;
    argv[1] = (char*)cfg->nameservice;
    argv[2] = NULL;

    CORBA::ORB_var m_varOrb = CORBA::ORB_init( argc, argv, cfg->id );

    pthread_mutex_unlock( &mutex );
    return NULL;
}

Итак, когда mt равно false, все в порядке, я могу расширить код для создания некоторых объектов, специфичных для сервера, для выполнения различных запросов и т. д. Но тогда mt равно true, второй поток не вызывает ORB_init. См. трассировку стека ниже.

Я почти уверен, что упускаю что-то очень простое и глупое, но что?

$ g++ -g3 -ggdb -Wall -Wshadow -march=i486 
      -DUNIX -DLINUX -DPTHREADS -DMULTITHREAD -D_REENTRANT
      -I. -I/usr/local/include/OB/ -I/usr/local/include/JTC/ 
      -I/usr/include/OB/ -I/usr/include/JTC/ -L/usr/local/lib 
      -lpthread -lm -lz -lrt -ldl -lOB -lJTC -lCosNaming 
      test.cpp

Трассировки стека:

#0  0x00566402 in __kernel_vsyscall ()
#1  0x0080dfd0 in raise () from /lib/i686/nosegneg/libc.so.6
#2  0x0080f9b1 in abort () from /lib/i686/nosegneg/libc.so.6
#3  0x03dc490b in ~RefCount 
    (this=Could not find the frame base for "~RefCount".) 
    at ../../include/OB/RefCount_Ts_Linux-x86-32.h:43
#4  0x03ef8965 in ORBInstance 
    (this=Could not find the frame base for "ORBInstance".) 
    at ORBInstance.cpp:276
#5  0x03f134fe in ORB_impl 
    (this=Could not find the frame base for "ORB_impl".) 
    at ORB_impl.cpp:281
#6  0x03f24740 in OBCORBA::ORB_init 
    (ac=Could not find the frame base for 
        "OBCORBA::ORB_init(int&, char**, OB::Properties*, 
                           OB::Logger*, OB::Reactor*, 
                           char const*, char const*)". ) 
    at ORB_init.cpp:994
#7  0x03f249d9 in CORBA::ORB_init 
    (ac=Could not find the frame base for 
         "CORBA::ORB_init(int&, char**, char const*, char const*)".) 
    at ORB_init.cpp:1014
#8  0x0804895d in run (arg=0xbfe8b544) at test_server.cpp:45
#9  0x007334d2 in start_thread () from /lib/i686/nosegneg/libpthread.so.0
#10 0x008b848e in clone () from /lib/i686/nosegneg/libc.so.6

  • В конце вашей функции потока попробуйте вызвать m_varOrb->shutdown(true), а затем m_VarOrb->destroy(). Таким образом, ORB будет очищен до того, как _var выйдет из области видимости и очистит то, на что он указывает. 22.10.2012
  • Вы также можете прочитать отличное руководство по CORBA, написанное Кираном Макхейлом, здесь: ciaranmchale.com/corba-explained -просто 22.10.2012
  • @BrianKelly - ну, это крошечный пример, воспроизводящий мою проблему, а не настоящий код. На самом деле функция run является членом класса, производным классом-оболочкой для потоков, внутри есть цикл while( m_bRunning ), и все потоки (обычно 4) должны работать одновременно. Итак, выполнение shutdown и destroy в конце этого run не является опциями (они выполняются в методе DoDisconnect, но это что-то другое. 23.10.2012
  • @BrianKelly - спасибо за учебник, я посмотрю его, я просмотрел множество руководств, руководств пользователя, книг (включая Advanced CORBA Programming) и т. д. Я никогда не видел ничего о такой среде, что я хочу сделать. 23.10.2012
  • Я хочу сказать, что отсутствие shutdown и destroy в вашем тестовом примере может быть причиной сбоя. 24.10.2012
  • @BrianKelly - сбой в ORB_init, я не могу выполнить shutdown и/или destroy до второй инициализации, так как хочу, чтобы все потоки работали параллельно. 24.10.2012
  • Ах, ну, я не мог видеть всю трассировку стека. Вы должны опубликовать это тоже. 24.10.2012
  • @BrianKelly - я добавил трассировку стека. 24.10.2012
  • Похоже на ошибку в ORB. Как насчет их поддержки? 26.10.2012
  • Ваш код работает только с одним экземпляром ORB? Я не могу поверить, что это так. 26.10.2012
  • @tuergeist - что именно ты имеешь в виду? Он отлично работает с одним ORB и одним потоком. Он отлично работает с одним шаром, разделенным между несколькими потоками. А это значит (пока) - только один сервер. Я нашел что-то вроде обходного пути, и я напишу его здесь, когда хорошо его протестирую. 26.10.2012
  • Почему бы вам не проконсультироваться со своим поставщиком ORB и не посмотреть, возможно ли создание нескольких экземпляров ORB в одном приложении? почему ты хочешь сделать это? 26.10.2012
  • @BrianNeal - это возможно. Вопрос - как именно? Я не думаю, что мне нужно связываться с поставщиком ORB для таких вещей. И я сомневаюсь, что это заслуживает отрицательного голосования. 26.10.2012
  • Откуда вы знаете, что это возможно? Я подозреваю, что большинство ORB не предназначены для работы нескольких экземпляров в одном и том же адресном пространстве. Что еще более важно, почему вы хотите это сделать? Что вы пытаетесь сделать, что, по вашему мнению, невозможно сделать с помощью только одного экземпляра ORB? 26.10.2012
  • @BrianNeal - почему я думаю, что это работает - см. мой пример, когда mt == false. Почему бы не использовать один экземпляр ORB - потому что до вчерашнего дня я думал, что невозможно использовать один экземпляр ORB для подключения к разным серверам, но я обнаружил, что могу использовать ORBInitRef несколько раз, так что это должно работать. Но делает мой код уродливее. И поскольку в одном потоке я могу создать более одного ORB, должен быть способ сделать это через разные потоки. Вам не кажется? 26.10.2012
  • Это поведение, зависящее от ORB. Я подозреваю, что большинство ORB не предназначены для одновременного вызова нескольких потоков ORB_init() из разных потоков. Вы можете попробовать заключить вызовы ORB_init() в скобки с помощью мьютекса или как-то сериализовать свои вызовы, чтобы увидеть, прекратится ли сбой. 26.10.2012
  • @BrianNeal - еще раз посмотрите мой пример. Есть такой мьютекс (глобальный), который блокируется/разблокируется, так что потоки синхронизируются (ORB_init не вызывается одновременно..) 26.10.2012
  • Ах, извините, я пропустил это. Я снова утверждаю, что то, что вы делаете, не указано в спецификации CORBA, и это будет зависеть от деталей реализации вашего ORB. ORB, с которыми я знаком, на самом деле даже не реализуют третий аргумент (идентификатор ORB) для ORB_init(), и я совершенно уверен, что они рухнут, если вы вызовете ORB_init() также из нескольких потоков. Удачи. 26.10.2012
  • @BrianNeal - я согласен с тобой. Сначала я думал, что это невозможно, и почти бросил это. Но поскольку он работает с одним потоком (используя идентификатор ORB), должен быть какой-то способ заставить его работать с большим количеством потоков. Это просто не имеет смысла (по крайней мере, для меня). Спасибо, что пожелали мне удачи. Если вы считаете мой вопрос разумным, пожалуйста, отмените свой отрицательный голос (если он, конечно, ваш). Было бы слишком долго объяснять, зачем мне это на самом деле нужно, но это разумно и обсуждалось с несколькими старшими инженерами, поверьте мне :) 26.10.2012
  • @KirilKirov Что вы имеете в виду под Но это означает (пока) - только один сервер. - Вам не нужно более одного экземпляра ORB. Это не имеет смысла. Пожалуйста, опишите более подробно вашу реальную проблему. Я чувствую, что вы думаете, что несколько ORB решают вашу проблему, но это не так. 27.10.2012
  • @tuergeist - моя настоящая проблема в том, что я хочу разные потоки для разных подключений к разным серверам. Я думал, что единственный возможный способ сделать это - иметь несколько ORB. Затем я спросил несколько шаров через разные потоки многопоточное многопоточное приложение клиента шаров">stackoverflow.com/questions/13009694/ где я получил ответ, как создать несколько шаров. Затем возникла новая проблема - как это сделать разными потоками, а не одним. Получив ответ на мой предыдущий вопрос, я исследовал немного больше, и я нашел.... 29.10.2012
  • @tuergeist - ...рассказывает о приложениях с несколькими ORB. Вот почему я разместил этот вопрос. Позже оказалось, что есть другое решение, которое я опубликовал в своем собственном ответе ниже. Я думаю, что все это хорошо описано в моем вопросе + ответ, но неважно. Теперь достаточно ясно? 29.10.2012
  • @KirilKirov ORB будет использовать разные подключения (и потоки) к разным серверам каждый раз - всегда. Получение ответов и входящие вызовы также обрабатываются в разных потоках. Я думаю, вы пытаетесь решить проблемы, которые ORB уже решил за вас. Это промежуточное программное обеспечение, не пугайтесь многопоточности и прочего. Это уже сделали специалисты CORBA. 30.10.2012

Ответы:


1

Я нашел что-то вроде обходного пути. Делает мой код действительно уродливым и непростым для поддержки, но все же это что-то.

Вот что я сделал:

  • добавить механизм (в моем приложении), который будет считать необходимые потоки перед их запуском
  • заранее прочитайте конфигурации - мне нужно знать необходимые параметры для службы именования (используется в ORB_init)
  • перед запуском любых потоков "менеджер" выполнит только один раз ORB_init, но он будет передавать несколько раз параметр -ORBInitRef с разными значениями - по одному для каждого потока/соединения
  • после этого потоки запускаются, но вместо выполнения ORB_init они напрямую выполняют resolve_initial_references и продолжают работу со специфическими для сервера вещами.

Примечание: мой пример не содержит resolve_initial_references, потому что сбой происходит в ORB_init.


Итак, применение этого «алгоритма» для этого «обходного пути» будет выглядеть так:

#include <OB/CORBA.h>

void* run( void * );
CORBA::ORB_var varORB;

int main()
{
    /** The necessary configurations */
    //-------------------------------------v
    const char* nameservice1 = "NameService1=corbaloc::10.102.8.15:13069/NameService";
    const char* nameservice2 = "NameService2=corbaloc::192.168.1.99:13069/NameService";
    //-------------------------------------^

    /** INIT the ORB **/
    int argc = 5; char* argv[ 6 ];
    const char* initref = "-ORBInitRef";
    const char* exe = "test";

    argv[0] = (char*)exe;
    argv[1] = (char*)initref; argv[2] = (char*)nameservice1;
    argv[3] = (char*)initref; argv[4] = (char*)nameservice2;
    argv[5] = NULL;

    varORB = CORBA::ORB_init( argc, argv );

    pthread_t t1, t2; 

    char ns_id1 = '1', ns_id2 = '2';
    pthread_create( &t1, NULL, run, (void*)&ns_id1 );  
    pthread_create( &t2, NULL, run, (void*)&ns_id2 );  

    pthread_join( t1, NULL ); pthread_join( t2, NULL );

    varORB->destroy();

    return 0;
}
void* run( void* arg )
{
    char nameservice[] = "NameServiceN";

    // set the right number of the nameservice
    nameservice[ 11 ] = *((char*)arg);  

    varORB->resolve_initial_references( nameservice );

    // do some CORBA-specific stuff

    printf( "SUCCESS %c\n", *(char*)arg );
    return NULL;
}

ПРИМЕЧАНИЕ

Я до сих пор не могу поверить, что это единственный вариант. Если вы внимательно посмотрите на мой код (в вопросе), вы увидите, что:

  • ВОЗМОЖНО иметь несколько ORB (см. случай с mt == false)
  • вызов ORB_init IS синхронизирован
  • идентификатор ORB IS реализован и работает нормально (опять же с mt == false)

Итак, это не фактический ответ на мой вопрос, это своего рода обходной путь.

Не имеет смысла (по крайней мере для меня) создавать несколько ORB в одном потоке, но не в нескольких потоках.

26.10.2012
  • Если бы у меня действительно была причина вызывать ORB_init() несколько раз, я бы сделал это именно так. :) omniORB, например, предполагает определенные вещи о потоке, который вызывает ORB_init(), поэтому вызов его снова с другим потоком, вероятно, запутает его. Я подозреваю, что то же самое верно и для вашего ORB. 26.10.2012
  • Пфффф, провал! Даже если объект ORB является shutdown и destroy-ed, он не может быть создан другим потоком! Повторно инициализировать его может только первый поток, вызвавший ORB_init в самом начале. Это просто смешно! Если я попытаюсь инициализировать его из другого потока (после того, как он был уничтожен), сбой будет таким же. Я действительно не могу поверить в это, черт возьми. 30.10.2012
  • Я все еще не уверен, почему вы хотите вызывать ORB_init несколько раз. Это потому, что вам нужно связаться с различными службами имен? Я не уверен, но я думаю, что вы должны иметь возможность инициализировать шар один раз, а затем создать ссылку на объект для каждой службы имен, используя orb.string_to_object(), используя какой-то URI для каждой службы имен. 01.11.2012

  • 2

    ORB будет использовать разные подключения (и потоки) к разным серверам каждый раз - всегда. Получение ответов и входящие вызовы также обрабатываются в разных потоках (если это полезно и/или необходимо).

    Я думаю, вы пытаетесь решить проблемы, которые ORB уже решил за вас. Это промежуточное программное обеспечение, не пугайтесь многопоточности и прочего. Это уже сделали специалисты CORBA.

    30.10.2012
  • Хорошо, еще немного обо всем приложении - у меня есть поток, который принимает запросы от другого приложения (не CORBA). Этот поток анализирует эти запросы и решает, что с ними делать. Эти запросы должны быть перенаправлены на один из несколько разных серверов CORBA. Другими словами, этот поток является своеобразным менеджером, он управляет несколькими потоками, подключенными к разным CORBA-серверам. Вот почему мне нужно иметь разные потоки, которые обрабатывают разные соединения с разными серверами CORBA в одном приложении. 30.10.2012
  • Это архитектура приложения с 25 000+ строк кода, которое работает с разными протоколами (более 20). Здесь часть CORBA является специфичной для протокола частью. Это архитектура коннектора, используемого приложением, которое должно иметь возможность взаимодействовать с любыми другими приложениями по любому протоколу. Я хочу сказать, что я не могу изменить архитектуру. 30.10.2012
  • Да, я понимаю. Я просто объяснил, что и почему я пытался сделать. 31.10.2012
  • Я дам вам награду, так как срок их действия скоро истечет благодаря вашим усилиям. Спасибо, это полезная информация, но на самом деле не отвечает на мой вопрос. 31.10.2012
  • Мне очень жаль, что это не соответствует вашему вопросу, и это не то, что вы ожидали получить. 31.10.2012
  • А, нет проблем, конечно. На данный момент у меня есть решение (мой ответ), мне просто интересно, почему вылетает случай, описанный в моем вопросе. Большое спасибо за помощь :) 31.10.2012
  • Новые материалы

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

    ИИ в аэрокосмической отрасли
    Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


    Для любых предложений по сайту: [email protected]