LINUX.ORG.RU

как работает select на unnamed pipe?

 ,


0

1

Здравствуйте!

Разбираюсь с тем, как сделать передачу данных между основным процессом и потомком(потоком). Создаю в процессе pipe, потом создаю потомка (по-идее теперь pipe принадлежит обоим), а так, как он закольцован, то запись в потомке ведёт к появлению данных в родителе, которую я хочу отловить по select.

Внизу пример. Но select не срабатывает почему-то. Просто завершается по таймеру.

Можете подсказать как тут быть?

#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <linux/unistd.h>
#include <fcntl.h>

using namespace std;
//Дескрипторы pipa
int client_pipe[2];

//Код потока
void * thr_loop(void * arg)
{
int i = 0;
	char wbuf[1024];
	while(1)
	{
	char num[33];
		strcpy(wbuf,"test ");
		sprintf(num,"%d",++i);
		strcat(wbuf,num);
		//Пишем в дескриптор для записи раз в секудну
		write(client_pipe[1],wbuf,10);
		sleep(1);
	}
	pthread_exit((void * )0);
}


int main(int argc,char*argv[])
{

	pipe(client_pipe);
	
	fd_set pipes_set;
    FD_ZERO(&pipes_set);
	
	int max_pipe_num = 0;
	//Нашли максимальный pipe
	if (client_pipe[0] > max_pipe_num)	max_pipe_num = client_pipe[0];
	if (client_pipe[1] > max_pipe_num)	max_pipe_num = client_pipe[1];	

	//Старт потомка
	pthread_t _thread;
	pthread_create(&_thread, NULL, thr_loop, NULL);
	while(1)
    {
			struct timeval tv;
			const int n = 1024;
			char chprbuf[n];
			int chprbuf_len = 0;
			memset(&chprbuf,0,sizeof(chprbuf));
			tv.tv_sec = 1;
			tv.tv_usec = 0;
			//Ждём данные от потомка
			if(select(max_pipe_num + 1, &pipes_set, NULL, NULL, &tv) > 0)
			{
				chprbuf_len = read(client_pipe[0],chprbuf,n);
				if(chprbuf_len>0){
					string msg = string(chprbuf);
					cout<<msg<<endl;
				}
			}
    }
	pthread_join(_thread, NULL);
    exit(0);
}

Как минимум нужно перед select() сделать FD_SET(client_pipe[0], &pipes_set).

А так, в данном случае не проще ли read()-ом висеть?

deadskif
()

pipe используют для общения между процессами, а не потоками.

А так, кто будет устанавливать дескриптор в pipes_set?

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

Да, спасибо, это я пример переделал из основной проги. Там так и было. Но теперь пишет в зависимости от таймеров: если в потомке 1сек, а в select 2сек, то работает, а если наоборот, то нет. Странно. Я-то думал, что если потомок записал в pipe, а select при этом не слушал, то при последующем вызове select тот все поймёт( как минимум буферы будут в данными) и вызовется до таймера.

antp
() автор топика
Ответ на: комментарий от tailgunner

У меня задача не совсем как в примере. Там может создаваться много однотипных потоков и я хочу иногда обмениваться данными между потоком и основным процессом через pipe. Select удобен тем (как я думал), что в него можно от всех потоков дескрипторы закинуть и в основном цикле родителя вызывать select через какое-то время и смотреть - если пришло что от потомков - обрабатывать, а нет - завершаться там через 1 сек и делать ещё свои дела.

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

poll лучше

Действительно, прав tailgunner, переделал на poll и работает как надо - хоть где изменяй время цикла (хоть в потомке у sleep, хоть у родителя - у poll в timeout_msecs).

Спасибо.

 . . .
#include <poll.h>
using namespace std;
//Дескрипторы pipa
int client_pipe[2];
//Структура poll
struct pollfd fds[1];

//Код потока
void * thr_loop(void * arg)
{
int i = 0;
	char wbuf[1024];
	while(1)
	{
	char num[33];
		strcpy(wbuf,"test ");
		sprintf(num,"%d",++i);
		strcat(wbuf,num);
		//Пишем в дескриптор для записи
		write(client_pipe[1],wbuf,10);
		sleep(5);
	}
	pthread_exit((void * )0);
}


int main(int argc,char*argv[])
{

	pipe(client_pipe);
	
	fds[0].fd = client_pipe[0];
	fds[0].events = POLLIN | POLLRDBAND;

	//Старт потомка
	pthread_t _thread;
	pthread_create(&_thread, NULL, thr_loop, NULL);
	while(1)
    {
			int timeout_msecs = 1;
			const int n = 1024;
			char chprbuf[n];
			int chprbuf_len = 0;
			memset(&chprbuf,0,sizeof(chprbuf));

			//Ждём данные от потомка
			if(poll(fds, 1, timeout_msecs)>0)
			{
				chprbuf_len = read(client_pipe[0],chprbuf,n);
				if(chprbuf_len>0){
					string msg = string(chprbuf);
					cout<<msg<<endl;
				}
			}
    }
	pthread_join(_thread, NULL);
    exit(0);
}
antp
() автор топика
Ответ на: комментарий от antp

обьяснить как пользоваться select ? man читать пробовали ? примеров в гугле полно, FD_SET у вас нет

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

poll такой же готовый как select, маны надо читать

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