LINUX.ORG.RU

Сигнал c установленным пользоветльским обработчиком не прерывает вызовы select и poll

 , ,


0

2

В констуркторе класса у меня следующие строчки:

sigset_t sset;
::sigfillset(&sset);
::sigdelset(&sset, SIGINT);
::sigprocmask(SIG_SETMASK, &sset, 0);
struct sigaction sa;
sa.sa_handler = Server::finishWork;
sa.sa_flags = SA_INTERRUPT;
sa.sa_mask = sset;
::sigaction(SIGINT, &sa, 0);

обработчик для сигнала сейчас выглядит так ( за cout не бейте ):

    static void finishWork(int) {
    std::cout << "YES!\n";
    isFinished_ = true;
}

Смысл в том, что запускаются два потока: один получает сообщения по именованному каналу и кладет их в очередь, а другой вынимает. В том потоке, что принимает сообщения есть select ( менял на poll). Этот select бесконечный.

Надежда была на то, что при получении сигнала select прервется, однако этого не происходит...

Ответ на: комментарий от Impossibility

Возможно, поможет статья с хабра.

http://habrahabr.ru/post/141206/

Предположу, что обработчик вызывается для главной нити. Что-бы он отработал в треде, возможно, нужно воспользоваться pthread_kill.

Еще одно предложение - заменить poll()/select на ppoll()/pselect().

Dead ★★★★
()
Последнее исправление: Dead (всего исправлений: 3)

Такое впечатление, что у тебя где-то стоит SA_RESTART (_BSD_SOURCE определен или что-то такое).

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

Ну, здесь универсальный совет - пусти программу под strace и посмотри аргументы системного вызова sigaction (или как он там называется).

tailgunner ★★★★★
()

Бред какой-то. Вы не показываете собственно кода, который работает не так, как вам хочется. Зачем здесь сигнал, неясно. Почему бы вам не ожидать select-ом сам канал, в котором появляются данные? select сам замечательно прервётся. Если канал какой-то хитрый, и его нельзя слушать select-ом, добавьте параллельный сигнальный канал, который селектом слушать можно, и шлите туда немножко данных, чтобы селект прервался (пример можно посмотреть в коде Asterisk, например).

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

Действительно. strace говорит ,что sigaction вызывается с sa.sa_flags = SA_RESTORER | SA_INTERRUPT. Буду курить man'ы...

Impossibility
() автор топика
Ответ на: комментарий от Krieger_Od
#ifndef LED_CONTROL_SERVER_H_
#define LED_CONTROL_SERVER_H_

/*
 * developer: Kuksov Pavel
 * mail: aimed.fire@gmail.com
 */

#include "MessageHandler.h"
#include "MessageQueue.h"
#include "LastDataCommand.h"

#include <thread>
#include <algorithm>

#include <sys/signal.h>

namespace LedControl {

class Server {
public:
	Server (MessageHandler* mh);

	static void finishWork(int) {
		std::cout << "YES!\n";
		isFinished_ = true;
	}

	void getRequests() noexcept;

	void setAnswers() noexcept;


	void run(size_t numberOfThreads) noexcept;

private:
	static const std::string LAST_DATA;

	static volatile bool isFinished_;

	size_t numberOfThreads_;
	MessageHandler* mh_;
	MessageQueue taskQueue_;
};//end of declaration class Server

} /* LedControl */ 

#endif /* end of include guard: LED_CONTROL_SERVER_H_ */
#include "Server.h"


namespace LedControl {

const std::string Server::LAST_DATA = "last_data";

volatile bool Server::isFinished_ = false;

Server::Server(MessageHandler* mh): numberOfThreads_(0), mh_(mh) {
	//блокируем все сигналы кроме SIGINT
	sigset_t sset;
	::sigfillset(&sset);
	::sigdelset(&sset, SIGINT);
	::sigprocmask(SIG_SETMASK, &sset, 0);
	struct sigaction sa;
	sa.sa_handler = Server::finishWork;
	sa.sa_flags = SA_INTERRUPT;
	sa.sa_mask = sset;
	::sigaction(SIGINT, &sa, 0);
}//end of Server::Server()

void Server::getRequests() noexcept {
	static LastDataCommand lastCommand(LAST_DATA);

	while ( isFinished_ != true ) {
		Command* cm = mh_->getRequest();
		if ( cm != nullptr ) {
			taskQueue_.enqueue(cm);
		}//end of if 
	}//end of while

	for (size_t i = 0; i < numberOfThreads_ - 1; ++i) {
		taskQueue_.enqueue(&lastCommand);
	}//end of for
	std::cout << "END of main thread!\n";
}//end of void Server::getRequests()

void Server::setAnswers() noexcept {
	while ( isFinished_ != true ) {
		Command* cm = taskQueue_.dequeue();
		if ( cm->getClientId() != LAST_DATA ) {
			mh_->giveAnswer(cm);
		} // end of if
	}//end of while
}//end of void Server::setAnswers()

void Server::run(size_t numberOfThreads) noexcept {
	size_t numberOfThreads_ = numberOfThreads;
	if ( numberOfThreads_ > 10 ) {
		numberOfThreads_ = 2;
	}//end of if 

	if ( numberOfThreads_ > 1 ) {
		std::vector<std::thread> threads(numberOfThreads_);
		threads[0] = std::thread(&Server::getRequests, this);
		for (size_t i = 1; i < threads.size(); ++i) {
			threads[i] = std::thread(&Server::setAnswers, this);
		}//end of for

		std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));
	} else {
		while ( isFinished_ != true ) {
			Command* cm = mh_->getRequest();
			mh_->giveAnswer(cm);
		}//end of while
	}

}//end of void Server::run()

} /* LedControl */ 

остальной код: https://github.com/verdandi/LedControl

Impossibility
() автор топика

SIGINTERRUPT(3)

Прерывать системные вызовы сигналом, имхо, сомнительная практика. Пользуйте siginterrupt(3).

Northsoft ★★
()

Так я и не разобрался. Пошел по пути товарища Krieger_Od - проще и надежнее. Над сигналами еще покурю - тут моя невнимательность сыграла роль.

Всем большое спасибо.

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