LINUX.ORG.RU

phtread и fork()


0

0

Есть код на С++.

Используется fork() и phthrad.

class thread {

	public :
		virtual ~thread(){}

		virtual void *init() = 0;

		int start(){
			int n = pthread_create(&pth_, 0, &real_run, this);
			pthread_detach(pth_);
			return n;
		}

		int stop(){pthread_exit(this);}

		pthread_t id() const{
			return pth_;
		}

	private :
		pthread_t pth_;
		static void * real_run(void *arg){
  			thread *t = static_cast<thread *>(arg);
 			return t->init();
		}
};

class vol : public thread{

	public:
		vol();
	
	private:
		void test(){printf(">>> echo from thread\n");};
		void *init(){test();};
};

vol::vol()
{}

int main()
{
	int pid = 0;

	printf("> create vol\n");
	vol *v = new vol();
	printf("> start fork\n");
	if ((pid = fork()) < 0) 
	{
		printf("> can't fork\n");
	} else if (pid != 0) {
		printf("> fork success\n");
		exit(0);
	}
	printf("> start thread\n");
	v->start();
	printf("> ready\n");
}

на выходе

./prog
> create vol
> start fork
> fork success
> start thread
> ready

... не выводится >>> echo from thread

Проблема в том, что не происходит запуска потока. Есть ли способ запускать поток и использовать fork().

Заранее спасибо!

★★★★★

void test(){printf(«>>> echo from thread\n»);};

vol::vol()

{}

Функция приватная, в конструкторе или ещё где-то не используется. Или я чего-то не понимаю в тонкостях pthread.

ShTH
()

А что тебя удивляет? Синхронизацией ты вообще не озаботился. Твой процесс может завершиться еще до того, как в нем начнет выполняться вторая нить.

tailgunner ★★★★★
()

Ну на самом деле pthread_create выполняется всегда (то есть синхронная часть).
Далее твой поток начинает выполняться асинхронно относительно дочернего процесса. Так как очередность выполнения не определена, дочерний процесс _может_ завершиться раньше чем поток начнет выполняться.
В твоем случае это происходит всегда, но это не гарантировано никак и если ты запустишь прогу 1000 раз, то велик шанс что ты увидишь таки «>>> echo from thread» (если поток будет диспетчеризирован на выполнение «раньше» основного потока дочернего процесса).

Чтобы не зависить от этих рэйсов нужно синхронизировать выполнение потоков. Как вариант можешь убрать pthread_detach и добавить последней строчкой main'а
pthread_join(v->id(), 0);

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

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

С этим примером есть одна неприятная ситуация.
Ты фактически реализовал то, что называется Active Object Pattern (если я еще что-то помню из POSA :))
Твой объект класса vol создается как пассивный, затем после выполнения v->start() он становится активным (есть отдельный поток управления, который выполняется независимо от основного и использует состояние объекта). После завершения потока объект вновь становится пассивным.

Так вот проблема в том, что если ты создаешь поток как detached, то непонятно как понять что объект стал пассивным.
Это важно, так как только пассивный объект можно удалять (в твоем примере память течет).

Использование флага типа

class val
{
...
int passive_again;
public:
bool is_passive() const {return passive_again;}
void set_passive() {passive_again = 1;}
...
}

И установка в конце run функции потока не канает:

void* val::run()
{
// Do something
...
set_passive();
// But I'm still active at this point
return 0;
}

так как после вызова set_passive объект по факту все еще активный, но is_passive, вызванный например из других потоков, будет возвращать true.
А это дает право удалить все еще активный объект.

Это типа FYI, чтобы не ловить типичные ошибки :)

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

> Это важно, так как только пассивный объект можно удалять (в твоем примере память течет).

pthread_cancel()/pthread_exit() можно вызывать вне зависимости от состояния потока. А явный вызов pthread_detach() позволяет системе освободить память, связанную с потоком, сразу после его завершения (аналогично, если создавать поток с PTHREAD_CREATE_DETACHED).

А это дает право удалить все еще активный объект.

Так проще:

bool is_active(void) const { return !pthread_kill(this->pth_, 0); }

sjinks ★★★
()

cyclon, в Вашем случае еще имеет смысл метод int thread::stop() сделать protected. Так как если Вы вызовите stop() из другого потока, то завершите вызвавший поток, а не вызываемый.

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