LINUX.ORG.RU

C++ как проверить поток.

 , ,


1

4

Добрый всем. Есть задачка, опрашивать датчик через определенный интервал времени (время опроса датчика не должно прерываться). После заполнения файла temp.txt он копируется по сети (далее создается новый файл temp.txt) и так по кругу.

Для реализации задачи я в программе запустил 2 потока, первый делает опрос, второй копирует данные.

Функция копирования файла для 2-го потока.

void CopyNetFile(std::string path) {
        DIR *dir;
        char dirbuffer[150];
        const char * test_path = path.c_str();
        strcpy(dirbuffer, test_path);
        dir = opendir(dirbuffer);

        if ( dir == NULL ) {
                printf("Каталог не доступен (копируй локально\n");
        }else{
                printf("DIR YES\n");
                std::string nametime = ""+path+"file.txt";
                std::string nametemp = "temp.txt";
                const char* p_c_nametemp = nametemp.c_str();
                const char* p_c_nametime = nametime.c_str();

                std::ifstream in(p_c_nametemp); // open original file
                std::ofstream out(p_c_nametime); // open target file
                out << in.rdbuf(); // read original file into target
                out.close(); // explicit close, unnecessary in this case
                in.close();// explicit close, unnecessary in this case
                unlink (p_c_nametemp);//удаляем файл
        }
}
Основной поток main
#include <thread>
int main(int argc,char *argv[]) {
   while (1){
      опрос датчика...
      if (пришло время копировать) {
         //Запускаем в отдельном потоке функцию 
         std::thread copy_thread(CopyNetFile,path);
         //Не дожидаемся выполнения функции продолжаем работу основного потока. 
         copy_thread.detach();
      }
   }
}
Все компилируется и копируется.
С потоками работаю первый раз, не знаю как проверить есть остановка основного потока или нет.

Можно, просто дождаться в основном потоке завершения рабочего потока (thread::join).

Можно, если позволяет алгоритм, вставить проверку флага о завершении основного потока и защитить его мьютексом(std::mutex).

Ещё, можно использовать низкоуровневое апи типа pthread_cancell, что бы прервать текущий блокирующий вызов и ускорить завершение рабочего потока.

В любом случае, надо написать обработчик сигналов.

pon4ik ★★★★★ ()

опрашивать датчик через определенный интервал времени.

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

int done = 0;

signal_handler() {
    done = 1;
}

thread_func() {
    while (done == 0) {
        // получить данные
        // записать в очередь
    }
}

main() {
    // зарегистрировать signal_handler
    // thread_handler = запустить поток
    while (done == 0) {
        // вычислить, сколько времени осталось до следующей отправки
        // заснуть на это время
        // забрать данные из очереди
        // отправить данные
    }
    // join thread_handler
}
gag ★★★★★ ()
Ответ на: комментарий от annulen

std::thread

/0

...лишь обертка над fork(), который обертка над sys_clone, который обертка над ядрёнными кишками. Суть вопроса то не в языке, а в алгоритме, а тут всего-то с головой дружить нужно.

anonymous ()

Тут скорее всего нужны очередь.
В основном потоке пушим в очередь данные. В другом потоке читаем и записываем в файл. Пересоздавать поток каждый раз не нужно.

tyamur ()

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

У нас часто спрашивают: «Зачем вы пилите свой фреймворк?» А вот затем и пилим, чтобы не нужно было вручную колупаться с рабочими нитями и передачей информации между ними. Чтобы неопытный разработчик мог писать многопоточный код и не задумывался сильно о том, а завершаются ли у него нити, корректно ли он сделал thread-safe message queue и т.д.

Остается только пожалеть о том, что когда людям в C++ приходится сталкиваться с многопоточностью, то изучать это дело начинают именно с std::thread+std::mutex+std::condition_variable. А не с более высокоуровневых вещей, вроде CSP, task-based parallelism, fork-join, actors и т.д. :(

Задача ТС-а на SObjectizer-е с использованием модели CSP может быть реализована вот в таком виде. Ручная работа с std::thread нужна только чтобы рабочую нить запустить. Потом можно работать с более удобными и более высокоуровневыми абстракциями.

eao197 ★★★★★ ()
Ответ на: комментарий от eao197
			[&](so_5::mhood_t<acquisition_turn>) {
				// Имитируем опрос датчика.
				std::cout << "meter read started" << std::endl;
				std::this_thread::sleep_for(50ms);
				std::cout << "meter read finished" << std::endl;

				// Отдаем команду на запись нового файла.
				so_5::send<write_data>(file_write_ch,
						"data_" + std::to_string(ordinal) + ".dat");

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

	receive(from(file_write_ch),
			// Этот обработчик будет вызван когда в канал попадет
			// сообщение типа write_data.
			[&](so_5::mhood_t<write_data> cmd) {
				// Имитируем запись в файл.
				std::cout << cmd->file_name_ << ": write started" << std::endl;
				std::this_thread::sleep_for(350ms);
				std::cout << cmd->file_name_ << ": write finished" << std::endl;

В обработке очереди на запись пауза дольше (для накопления?), но из очереди (канала) изымается только один файл, тогда очередь будет постоянно увеличиваться. Если же (после очередных 350 мс) из канала вынимаются все пришедшие сообщения, то будут созданы десятки/сотни/... новых потоков, чтобы записать файлы и снова заснуть или что-то поэффективнее? Вот, что мне видно без заглядывания в описание SObjectizer.

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

Вы ошибаетесь. Либо не внимательно посмотрели, либо не в курсе, как работают CSP-шные каналы.

Запись данных в новый файл здесь имитируется просто для примера. Кроме того, данные снимаются раз в 750ms. И новые потоки на каждый файл не создаются.

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

Тут скорее всего нужны очередь.

Да, полностью согласен. Взгляни в сторону libuv. Там есть таймер. Как я понимаю должно выглядеть так: 1. Таймер пушит в очередь сообщение с нужным интервалом. 2. Main или еще кто пулит очередь. 3. Если файл заполнился - кидаем в очередь сообщение «перекинь этот файл по сети и странкейть его».

Вот в общем то и весь цикл. Основная опасность - если какая-то операция будет длится больше периода таймера (очередь начнет рости). Для этого есть свои методы решения.

P.S.: Выбор подхода очень важен в решении. Если и можно как-то решить задачу в несколько потоков, то возникает множество краевых условий, что перегрузит код (и никто не захочет в нем разбираться, даже ты через неделю).

anonymous ()