Как осуществить многопоточный запуск программ в linux на си?

Я занимаюсь разработкой тестового ПО, для тестирования железа. И у меня стоит задача запускать тестирующие программы параллельно друг другу. И не просто запускать, а ещё и обрабатывать их вывод и результаты теста.

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

static id=0; //счётчик запущенных процессов
int runner(void * ini_file_data_st_ptr, LPVOID sys_hwd_ptr)
{
....
	int result;
	pthread_t th_usbtest, th_ledtest, th_comtest, th_framtest, th_hddtest;

// test USB
	if (ifd ->usbCount>0) { //если у нас есть тестирование USB
		id++; //увеличиваем счётчик
		result = pthread_create(&th_usbtest, NULL, usbtest, &id); //запускаем поток "usbtest"
		printf("Creating the usbtest thread\n");
	} 
//test LED
	if (ifd ->ledsFlag) {
		id++;
		result = pthread_create(&th_ledtest, NULL, ledtest, &id); //запускаем поток "ledtest"
	}
//test COM
	if (ifd ->comCount>0) {
		id++;
		result = pthread_create(&th_comtest, NULL, comtest, &id); //запускаем поток "comtest"
	}
//... и так далее остальные процессы

	while (id!=0) { //костыли для ожидания окончания работы процессов, чтобы не возиться с мьютексами и семафорами
		sleep(1);
	}
}


Все функции процессов (usbtest, ledtest, comtest и т.д.) примерно одинаковые. Поэтому я приведу пример одной из них.

#define USB_TEST_PATH "./usbtest"
void *usbtest (void *arg){
	FILE* f;
	ptrSysHWD->usbCount=0; //технические данные
	gl_tst_result.usb=true;
	char buf[128];
	char path[128];
	sprintf(path,"%s %d", USB_TEST_PATH, ifd ->usbCount); //формируем команду запуска программы с параметрами (передаём количество юсб)
	f = popen(path,"r"); //запускаем программу
	while (fgets(buf,127,f)) //читаем всё то что программа выводит
	{
// ********************* !!!
		printf("%s\n",buf); //выводим на экран
		fflush(stdout); // ФЛУШИМ!!!
// ********************* !!!
		if ((strstr(buf, "error") != NULL) || (strstr(buf, "not found") != NULL ) || (strstr(buf, "Error") != NULL) || (strstr(buf, "failed") != NULL)) {
				printf ("USB HARDWARE ERROR\n");
				gl_tst_result.usb=false;
		} //проверяем на ошибки
		if (strstr(buf, " OK!") != NULL) { //считаем количество устройств
			ptrSysHWD->usbCount++;
		}
	}
	fclose(f); //после того, как прочитали закрываем программу
	id--; //минусуем счётчик потока
}


Остальные потоки аналогичные, запускают другие аппаратные тесты. Фишка в том, что некоторые тесты могут выполняться по несколько десятков секунд. И вот парадокс, что несмотря на fflush(stdout); у меня в логах идёт последовательный вывод всех программ. Т.е. я понимаю так, что если потоки работают параллельно и дескрипторы открытых файлов стандартного вывода одинаковые, то у них должен быть перекрещивающийся вывод. А этого нет.

Из чего можно заключить: потоки и программы выполняются ПОСЛЕДОВАТЕЛЬНО! Хотя запуск каждого потока идёт параллельно. Что я делаю не так? И как это исправить?
  • Вопрос задан
  • 5134 просмотра
Решения вопроса 2
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
//костыли для ожидания окончания работы процессов, чтобы не возиться с мьютексами и семафорами

Достаточно вызвать pthread_join для каждого из запущенных потоков.

fclose(f); //после того, как прочитали закрываем программу

Должно быть pclose(f).

id--; //минусуем счётчик потока

Зря вы так, грязными руками в общую переменную.

Из чего можно заключить: потоки и программы выполняются ПОСЛЕДОВАТЕЛЬНО

Non sequitur. Но для полноты картины хотелось бы увидеть Makefile.
Ответ написан
dlinyj
@dlinyj Автор вопроса
Большое спасибо за найденный косяк с pclose!!!

pthread_join - потоки могут завершиться в разное время, но вероятно так и надо сделать. Прикостылил, в силу незнания.

Мейкфайл - пожалуйста:

# Makefile for dlbht
TARGET = dht

CC ?= gcc
CXX ?= g++

CFLAGS = -O0 -g 
CXXFLGS = -00 -g 

LDFLAGS += -lpthread
#LDFLAGS += -g
CC = gcc

SRC = main.c
SRC += utils.c
SRC += readconf.c
SRC += chknint.c
SRC += runner.c
SRC += get_com_port_list.c
SRC += result.c

SRCPP=

OBJ = $(SRC:.c=.o)

all:
	make compile
	cp $(TARGET) ../bin
	cp test_std.cfg ../bin/

compile:
	make $(OBJ) 
	make $(TARGET)

$(TARGET):$(OBJ)
	$(CXX) -o $(TARGET) $(OBJ) $(LDFLAGS)
	
	#$(CC) -D_REENTERANT -o $(TARGET) -g $(OBJ) $(LDFLAGS)
	#strip $(TARGET)

get_com_port_list.o: get_com_port_list.cpp
	$(CXX)  -c -o get_com_port_list.o get_com_port_list.cpp

clean:
	rm -f *.o $(TARGET)  *.log
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы