LINUX.ORG.RU

Потоки и fork()


0

0

Пишу GUI приложение, которое использует gtkmm и boost. Недавно понадобилось запускать из него другие приложения, т. е. вызвать fork() и execlp.

Вот тут то и возник вопрос. fork() копирует только текущий поток. А как с остальными? Внутри GTK ведь тоже крутятся какие-то потоки - не будет ли конфликтов?

К тому же у меня в библиотеке есть глобальный скрытый singleton класс, который создает boost'овский поток. Деструктор класса, соответственно, помечает переменную, которую данный поток проверяет и ждет завершения потока.

При выполнениее execlp выполняетя деструктор данного класса, но функция wait, которая ждет завершения потока не возвращает управление.

Подскажите, пожалуйста, как решаются такие проблемы.

anonymous

>При выполнениее execlp выполняетя деструктор данного класса

с чего бы это?

при fork() происходит создание второго _процесса_, в котором нужно настроить окружение для запуска execlp. код из boost/gtkmm/whatever не запускается _автоматически_ по fork(), поэтому деструкторы _автоматически_ вызваны не будут.

>но функция wait, которая ждет завершения потока не возвращает управление.


тут подробнее плз.

generatorglukoff ★★
()
Ответ на: комментарий от generatorglukoff

> с чего бы это?
Как это понимаю я:
Т. к. объект глобальный, то вызов execlp() как и, например, вызов exit() вызывает его деструктор.

> тут подробнее плз.
В потоке бесконечный цикл. В нем блокировка на семафоре. Если нужно выполнить очередную задачу, семафор разблокируется, поток просыпается, выполняет задачу и снова засыпает. Если нужно завершить поток, то некоторая переменная выставляется в 1 и разблокируется семафор. Поток просыпается, проверяет эту переменную и завершает свою работу.

В деструкторе у меня эта переменная выставляется в 1 и производится вызов this->wait(), который ждет завершения потока. Т. к. при fork() копируется только тот поток, из которого fork() был вызван, то boost'овский поток в дочернем процессе отсутсвует. Т. е. boost думает, что он есть, а на самом деле его нет и, соответственно, некому проверить значение этой переменной и завершить поток. Поэтому вызов wait() блокируется навсегда.

anonymous
()
Ответ на: комментарий от anonymous

>Т. к. объект глобальный, то вызов execlp() как и, например, вызов exit() вызывает его деструктор.

не-а

andrey@valkyrie ~ $ cat dummy.cpp
#include <iostream>
#include <sys/types.h>
#include <unistd.h>


using namespace std;

class dummy
{
 public:
  ~dummy()
  {
   cout << "dummy of process " << getpid() << " terminating" << endl;
  }
};

dummy d;

int main()
{
 if(fork())
 {
  cout << "new process " << getpid() << endl;
  execlp("echo", "echo", "Hello world!\n", NULL);
 }
 return 0;
}
andrey@valkyrie ~ $ g++ dummy.cpp
andrey@valkyrie ~ $ ./a.out
new process 27999
Hello world!

dummy of process 28000 terminating
andrey@valkyrie ~ $

generatorglukoff ★★
()
Ответ на: комментарий от anonymous

>В деструкторе у меня эта переменная выставляется в 1 и производится вызов this->wait(), который ждет завершения потока. Т. к. при fork() копируется только тот поток, из которого fork() был вызван, то boost'овский поток в дочернем процессе отсутсвует. Т. е. boost думает, что он есть, а на самом деле его нет и, соответственно, некому проверить значение этой переменной и завершить поток. Поэтому вызов wait() блокируется навсегда.

1. что такое this?
2. что такое wait у этого this?
3. man 2 wait нужно вызывать в родителе

generatorglukoff ★★
()
Ответ на: комментарий от generatorglukoff

> блин, затупил, if(fork() == 0), впрочем это не меняет сути того, что при execlp деструктор не вызывается

мне почему то кажется, что для глобальных объектов при exec() деструктор должен вызываться. с точки зрения дальнейшего жизненного пути приложения exec() - это тот же самый exit().

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от klalafuda

>мне почему то кажется, что для глобальных объектов при exec() деструктор должен вызываться. с точки зрения дальнейшего жизненного пути приложения exec() - это тот же самый exit().

но не вызывает же…

generatorglukoff ★★
()
Ответ на: комментарий от generatorglukoff

> но не вызывает же…

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

// wbr

klalafuda ★☆☆
()

Ой, да я вас всех обманул. :(
Все, что я описал выше, происходит тогда, когда execlp() возвращает ошибку и я делаю exit(1). :) Извините, пожалуйста, _exit(1) устранил эту проблему.

Небольшой оффтопик:
После вызова fork() мне необходимо закрыть все открытые файловые дескрипторы (кроме 0, 1. 2) и все? Этого достаточно? Вся память, которая была выделена malloc'ом и при помощи new автоматически освободится системой?

А вот если, например, у меня было что-то вроде:
> std::string string = "sample_string";
> fork();
Могу ли я использовать string в обоих процессах? Корректно ли она скопируется, или ее можно использовать только в родительском процессе?

anonymous
()
Ответ на: комментарий от anonymous

>После вызова fork() мне необходимо закрыть все открытые файловые дескрипторы (кроме 0, 1. 2) и все? Этого достаточно?

скорее всего да

>Вся память, которая была выделена malloc'ом и при помощи new автоматически освободится системой?


по fork ты получаешь абсолютный дубль процесса, вместе с данными и кучей.
если ты делаешь execlp то вся память уничтожается и заменяется новой.

generatorglukoff ★★
()

Премного благодарен всем за помощь!

anonymous
()
Ответ на: комментарий от klalafuda

>мне почему то кажется, что для глобальных объектов при exec() деструктор должен вызываться. с точки зрения дальнейшего жизненного пути приложения exec() - это тот же самый exit().

Деструкторы региструруются через atexit() и вызываются libc при выходе из main(), exit() либо получении сигнала который LIBC перехвачен. POSIX 2 my mind лежит уровнем ниже и его проблемы libc не очень беспокоят.

Absurd ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.