nixp.ru v3.0

10 ноября 2026,
вторник,
19:57:08 MSK

Совместное использование обьекта процессами

Et cetera → Программирование

Longobard написал 9 января 2006 года в 00:20 (913 просмотра) Ведет себя как мужчина; открыл 291 тему в форуме, оставил 2499 комментариев на сайте.

Задача такая:

есть обьект класса X, нужно вызывать его методы из различных процессов. Если вместо процессов использовать треды — то все просто, храним его в памяти процесса и обращаемся к обьекту по указателю из тредов, ибо треды выполняются в том же адресном пространстве, что и процесс, создавший тред.

А как быть в случае с несколькими процессами? Что-то никаких идей нету. Копировать обьект нельзя, он должен быть в единственном экземпляре. Нужно вызвать некоторые методы этого обьекта, в общем иметь к нему доступ. Помогите советом :)

Спасибо :)

Uncle Theodore

Определи сегмент shared memory, сообщи его адрес всем процессам и приаатачь. Засунь свой объект в общую память и пользуй изо всех процессов. Больше никак.

Good Luck,

UT

vkle

Может быть pipe или socket сойдет?

Longobard
Uncle Theodore
Определи сегмент shared memory, сообщи его адрес всем процессам и приаатачь. Засунь свой объект в общую память и пользуй изо всех процессов. Больше никак.

Good Luck,

UT

Как засунуть — понятно (Стивенс есть). А как вызвать метод обьекта, находящегося в общей памяти, без копирования его в память процесса?

Uncle Theodore
LONGOBARD
Как засунуть — понятно (Стивенс есть). А как вызвать метод обьекта, находящегося в общей памяти, без копирования его в память процесса?

Не понял вопроса. Приаттаченный сегмент памяти находится в адресном пространстве всех процессов, которые его приаттачили. Просто вызывай свой метод.

Good Luck,

UT

rgo
LONGOBARD
Как засунуть — понятно (Стивенс есть). А как вызвать метод обьекта, находящегося в общей памяти, без копирования его в память процесса?

Моих познаний для ответа на этот вопрос не хватает жутко: как грузиться elf, как g++ оформляет вызов virtual методов, и куча вопросов о shared memory (ну не пользовался я ею не разу) для меня остаются загадкой.

Но попробуй затолкать все объекты которые надо так использовать в libmylib.so, и компоновать приложения с -lmylib. Есть у меня подозрение, что тогда адреса всех функций класса окажутся одинаковыми в обоих процессах, и, может быть, даже будут вызываться без SEGFAULT и прочих сигналов.

Uncle Theodore

Напишу подробнее

хедер: myheader.h

class myclass{
 int value;
 void mymethod(){
   //do something
  };
 myclass(int v){
   value = v;
  };
}

Первый процесс (создающий объект)

#include "myheader.h"
int main() {
  //obtain a key for the ipc stuff
  if((ipc_key = ftok(".", 'R')) == -1)
    {
      cout << "Error key generating!\n";
      return -1;
    };
  //obtain some memory
  if((mem_id = shmget(ipc_key,sizeof(myclass),IPC_CREAT|0666))==-1)
    {
      cout << "Error getting shared memory!\n";
      return -1;
    };
  //attach the segment
  myclass * pointer = (myclass *)shmat(mem_id, NULL, 0666);
  //mark the segment to be destroyed when last process detaches it
  shmctl(mem_id,IPC_RMID,NULL);
  
  //now, do stuff
  *pointer = myclass(12);
  pointer -> mymethod();
  //when done, detach
  shmdt(pointer);
  return 0;
}

Второй процесс должен знать memory id сегмента. Можно получить его при запуске или через pipe/сокет

Второй процесс:

#include "myheader.h"
int main()
{
 int mem_id = str2int(argv[1]);
 //str2int is a function of mine
 myclass *pointer = (myclass*)shmat(mem_id, NULL, 0666);
 pointer -> mymethod();
 //detach when done
 shmdt(pointer);
 return 0;
}

Конечно, надо еще следить, чтобы сегмент не был уничтожен первым процессом, прежде чем второй получит шанс его использовать. Но это уже тонкости…

Good Luck,

UT

rgo
Uncle Theodore
Напишу подробнее

…

угу это работает, но не для виртуальных функций…То есть если myclass::mymethod объявить как virtual оно не работает. Причём я не понял почему :(. Надо будет повтыкать в работу ld.

Longobard

Uncle Theodore:

Спасибо за подробный ответ!

Но что делать, если (например) обьект является обьектом шаблонного класса? Или же у него есть виртуальные функции, как быть тогда?

decvar
Или же у него есть виртуальные функции, как быть тогда

что значит шаблонного? если инстанс в памяти есть, и vtable для методов есть, то без разници что за класс. главное что бы ты смог докастить void* до него. а для этого надо что бы сам класс был не абстрактный…

ЗЫ

Или я не понял проблемы?

Uncle Theodore

Скорее всего, проблема в изменении имен функций в С++. Что с этим делать я не знаю, extern «C» запретит оверлоадинг напрочь. Наверное, придется изголяться… Избавляться от виртуальных функций, например.

Good Luck,

UT

rgo

не, имена там не причём.

Виртуальные функции не работают не из-за shared memory, и даже не из-за того что методы класса валяются в библиотеке. Ежели память под объект выделять не shmget, а malloc, тот же самый SEGFAULT вылетает. Зато если пользоваться new то всё нормально. То есть, конструкция `*pointer = new myclass;' делает что-то не то. Хотя что, собственно, не то, я так и не понял. Достало разбираться в реализации всех этих virtual call’ов.

В общем, вопрос к знатокам C++, как в C++ можно сказать оператору new, что кусок памяти уже выделен, и его осталось только привести в юзабельный вид. В BorlandC 3.1, такая фича была, как она использовалась не помню. И подозреваю что это было свойством borlandc++, а не c++, но фича была.

Uncle Theodore
rgo
не, имена там не причём.

Виртуальные функции не работают не из-за shared memory, и даже не из-за того что методы класса валяются в библиотеке. Ежели память под объект выделять не shmget, а malloc, тот же самый SEGFAULT вылетает. Зато если пользоваться new то всё нормально. То есть, конструкция `*pointer = new myclass;' делает что-то не то.

new вызывает конструктор. Мне удалось воспроизвести то, о чем ты говоришь (Извиняюсь за длинный пример, но мне было интересно).

#include 
using namespace std;
class virt
{
public:
  int value;
  virtual int display() = 0;
};
class concr: public virt
{
public:
  int display()
  {
    cout << "Displaying value " << value << endl;
    return value;
  };
};
int main()
{
  concr *pointer = (concr*)malloc(sizeof(concr));
// так -- сегфолт, но если откомментарить следующую строку --
// все очень путем. Или если заменить предыдущую
//строку на pointer = new concr
//  new(pointer) concr;
  pointer -> value = 12;
  pointer -> display();
  return 0;
};


В общем, вопрос к знатокам C++, как в C++ можно сказать оператору new, что кусок памяти уже выделен, и его осталось только привести в юзабельный вид. В BorlandC 3.1, такая фича была, как она использовалась не помню. И подозреваю что это было свойством borlandc++, а не c++, но фича была.

Вот так, наверное

new(pointer) concr;

Не думаю, что это фича Борланда, но почему-то не могу найти вразумительной ссылки…

Соответственно, что-то вроде этого надо делать для shmget

Good Luck,

UT

rgo

new(pointer) concr; //<-- в g++ это работает.

Но, похоже, что адреса функций таки разные :(. Непонятно, чего это мне вдруг в голову взбрело, что они одинаковые должны быть?

Хотя для не-виртуальных функций работает (это я про shmget и далее). Там система разрешения адресов символов работает. Одна странность осталась: если myclass не в .so класть, а статически линковать, то какие-то аберрации поведения класса наблюдаются :-/