Я использую функцию опрос() (Я думаю, что это может быть частью POSIX?) Функция C в моем классе C ++, чтобы получить событие при изменении файла. Кажется, это работает просто отлично, но теперь я также хочу иметь возможность заставить функцию завершать работу немедленно, когда мне нужно закрыть поток.
Я исследовал это и выдвинул пару идей, которые попробовал — например, попытаться послать сигнал, но я не мог понять, как заставить это работать.
В приведенном ниже коде (который не завершен на 100%, но должно быть достаточно для иллюстрации проблемы), у меня есть класс C ++, который запускает поток из конструктора и хочет очистить этот поток в деструкторе. Поток вызывает опрос() который возвращается при изменении файла, а затем сообщает об этом объекту делегата. Поток мониторинга зацикливается до FileMonitor объект указывает, что может выйти (используя метод, который возвращает bool).
В деструкторе, что бы я лайк сделать, это перевернуть bool, а затем сделать то, что вызывает опрос() немедленно выйти, а затем вызвать * pthread_join () *. Итак, любые идеи о том, как я могу сделать опрос() немедленно выйти?
Этот код предназначен для Linux (в частности, для Debian), но я также работаю над ним на Mac. В идеале API poll () должно работать в основном одинаково.
void * manage_fm(void *arg)
{
FileMonitor * theFileMonitor = (FileMonitor*)arg;
FileMonitorDelegate * delegate;
unsigned char c;
int fd = open(theFileMonitor->filepath2monitor(), O_RDWR);
int count;
ioctl(fd, FIONREAD, &count);
for (int i=0;i<count;++i) {
read(fd, &c, 1);
}
struct pollfd poller;
poller.fd = fd;
poller.events = POLLPRI;while (theFileMonitor->continue_managing_thread()) {
delegate = theFileMonitor->delegate;
if (poll(&poller, 1, -1) > 0) {
(void) read(fd, &c, 1);
if (delegate) {
delegate->fileChanged();
}
}
}
}
FileMonitor::FileMonitor( )
{
pthread_mutex_init(&mon_mutex, NULL);
manage_thread = true;
pthread_mutex_lock (&mon_mutex);
pthread_create(&thread_id, NULL, manage_fm, this);
pthread_mutex_unlock(&pin_mutex);
}
FileMonitor::~FileMonitor()
{
manage_thread = false;
// I would like to do something here to force the "poll" function to return immediately.
pthread_join(thread_id, NULL);
}
bool FileMonitor::continue_managing_thread()
{
return manage_thread;
}
const char * FileMonitor::filepath2monitor()
{
return "/some/example/file";
}
Добавьте канал в ваш класс файлового монитора и переключите ваш опрос, чтобы принять исходный дескриптор файла и дескриптор чтения канала для опроса. Если вы хотите разбудить ваш класс файлового монитора для проверки его на выход, отправьте байт через дескриптор записи канала, который пробудит ваш поток.
Если у вас есть большое количество этих файловых мониторов, есть вероятность, что вы можете достичь максимального количества файловых дескрипторов для процесса (см. Проверьте лимит открытого FD для данного процесса в Linux для деталей, в моей системе это 1024 soft, 4096 hard). Вы могли бы иметь несколько классов мониторов, совместно использующих один канал, если вы не возражаете против того, чтобы они все проснулись сразу, чтобы проверить индикатор выхода.
Вы должны использовать pthread переменная условия внутри (и непосредственно перед) poll
цикл, и другой поток вызывает pthread_cond_signal
Вы могли бы рассмотреть трубы (7) самостоятельно обмануть себя (например, иметь одну нить написать (2) байт — возможно, прямо перед pthread_cond_signal— к трубе Опрос (2)-под редакцией другой ветки). Смотрите также сигнал безопасности (7) а также вызов функций Qt из обработчиков сигналов Unix. Оба могут вдохновить вас.