LINUX.ORG.RU

[C] Вопрос по выполнению в потоке.

 


0

1

Доброго времени суток, господа. Собственно - вопрос в следующем. Имеются 2 подпрограммы, одна - рисует окно, вторая - таймер с этим окном взаимодействует. Подпрограмма таймера - имеет метод add_time_str - который позволяет назначить таймеру, некоторое время. Вызов подпрограмм выглядит следующим образом:

window_init();//создание окна
timer_init();//инициализация таймера
add_time_str("20");//установка времени
window_loop();// Обработка событий окна
window_destroy();
В связи с тем, что window_loop - цикл, и пока он не отработает программа не продолжит свою работу, я хочу поместить эти вызовы в отдельный поток. Собственно вопрос: как поместить эти вызовы в pthread правильно, и главное - как потом вызвать add_time_str из потока? Заранее благодарю за помощь.

PS: пока все мои попытки проделать данную операцию ведут к Interrupted system call и состоят из попыток адаптировать писание Рочкинда к своей ситуации.

Снимаю шляпу перед теми, кто понял эту муть.

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

Ну с дефолтный экземплом - вываливается в interrupted system call.

Кто-то не обрабатывает сигналы, которые рассылает таймер?

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

Я уже догадался, да-) Оки, перефразирую вопрос.

void* initThread(void* arg)
{
 window_init();//создание окна
 timer_init();//инициализация таймера
window_loop();//
}
int main()
{
pthread_t tid;
int thread;
thread = pthread_create(&tid,null,initThread,(void)arg);
тут многа кода
}
Поток создается, после чего работает несколько секунд - и падает. Вот я и спрашиваю, каким образом - вышеперечисленые методы завернуть в поток - правильно. Если- методы работают верно в потоке main.

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

Странно, но в main потоке то все нормально-(

void window_loop()
{
	XEvent event;
	for (;;)
	{
		XNextEvent(display, &event);
		switch (event.type)
		{
		case Expose:
		{
			window_repaint();

			break;
		}
		case ResizeRequest:
		{
			XResizeRequestEvent *resize = (XResizeRequestEvent *) &event;

			window_width = resize->width;
			window_height = resize->height;

			break;
		}
		default:
		{
			break;
		}
		}
	}
}

- код метода window_loop

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

Ага, ход рассуждения понял. Тоесть, дабы избежать сегфолта - мне надо в main обработать сигналы? Или же в коде самой подпрограммы таймера?

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

Окна то с помощью чего рисуются? Что-то мне не приходилось пока встречать тулкитов, где бы не было готовых процедур работы с таймером в основном цикле обработки событий. Нахрена спрашивается городить здесь собственные потоки.

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

Окно рисуется с помощью xwindow. Свой огород? В целях самообразования так сказать.

void* initTimer(void* arg)
{
	window_init();
	timer_init();
	window_loop();
}
int main()
{       pthread id;
        sigset_t sigmask;
	int terror,arg;
	if( terror = pthread_create(&id,NULL,initTimer,(void*)arg)) {
                        printf("Thread creation failed: %d\n", terror);
					}
	pthread_sigmask(SIG_BLOCK,&sigmask,0); 				
	pthread_join (id, NULL); 

}

Так вот. Если вызвать pthread_join - то мой поток работает, если не вызвать - опять падаем в сегфолт. Уже всю башку сломал.

Код timer.c

 #include "stdio.h"
#include "stdlib.h"
#include "signal.h"
#include "sys/time.h"
#include "time.h"
#include "timer.h"
#include "window.h"

int timer_value;

void timer_init()
{
	signal(SIGALRM, &timer_callback);

	struct timeval interval = { 1, 0 };
	struct timeval value = { 1, 0 };

	struct itimerval timerval;
	timerval.it_interval = interval;
	timerval.it_value = value;

	setitimer(ITIMER_REAL, &timerval, 0);
}

void timer_callback(int sign)
{
	if (timer_value > 0)
	{
		timer_value--;
	}

	window_repaint_send();
}

void timer_str(char *str)
{
	int hour, min, sec;

	if (timer_value)
	{
		hour = timer_value / 3600;
		min = timer_value % 3600 / 60;
		sec = timer_value % 3600 - min * 60;
	}
	else
	{
		time_t t = time(NULL);

		struct tm *lt = localtime(&t);

		hour = lt->tm_hour;
		min = lt->tm_min;
		sec = lt->tm_sec;
	}

	sprintf(str, "%.2i:%.2i:%.2i", hour, min, sec);
}

int timer_get_message(char *str)
{
	int min = 0;

	if (timer_value <= 60)
	{
		min = 1;
	}
	else if (timer_value <= 180)
	{
		min = 3;
	}
	else if (timer_value <= 300)
	{
		min = 5;
	}
	else
	{
		return 0;
	}

	sprintf(str, "Attention! Less than %i minutes!", min);

	return 1;
}

void timer_add_time(char *min_str)
{
	int sec = (int)(atof(min_str) * 60);

	timer_value += sec;
}

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

Если вызвать pthread_join - то мой поток работает,

ну логично, т.к. основной поток ждёт завершения дочернего, а в противном случае программа «заканчивается». Я бы window_loop делал в основном, а в отдельном бы потоке пусть бы был только таймер, что он в потоке таймера забыл?

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

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

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

ну и плюс - после pthread_join - на этом программа не заканчивается, там ещё идет куча рутины с сокетами etc. но эта часть отлажена, работает-)

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

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

и чем это будет отличаться от варианта в 1 поток, если у тебя опять и таймер и интерфейс в одном потоке, а ты хотел от этого избавиться.

ну и плюс - после pthread_join - на этом программа не заканчивается, там ещё идет куча рутины с сокетами etc. но эта часть отлажена, работает-)

какая разница то:

так яснее?

  |
  |+-----------+   <--------------- +
  |               |   mainloop      |
  |               +---------------- +
  |                         ^
  finish              ----- | thread killed

vs

  |
  |+-----------+   <--------------- +
  |               |   mainloop      |
  |               +---------------- +
  |                           |
  p_thread_wait  <---  ждём завершения
  |
 finish

формально если ты сделаешь в конце main for(;;) то всё будет работать

P.S. поправьте если не прав

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

Таймер и интерфейс к нему - я же говорю, это просто довесок к основной программе. Вот я и хочу запихнуть поток и формочку к нему в отдельную нитку, потому как - если в 1 поток делать, тупо на window_loop останавливаемся, потому как он работает до самого уничтожения формочки.

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

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

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

Плюс я до сих пор курю маны по pthread, но все равно возникает вопрос. Вот создал я таки, чудом нужный мне поток. Но - необходимо будет вызывать метод add_time_str. А из потока то как его вызвать в таком случае?

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

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

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

Может дело не в потоках, а в обработке сигналов. Попробуйте в начале программы вызвать XInitThreads() из #include <X11/Xlib.h>.

abalakin ★★
()

кошмар.

кошмар, какой кошмар. ты работаешь в аду для программистов?

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

Думается мне, что проблема таки сидит где-то в недрах window_loop. Но спасибо за советы, сделаю через 2 потока.

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

Прикрутил поток обработки сигналов,


void* checkSignal()
{
sigset_t set;
int sig;

sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGALRM);
pthread_sigmask(SIG_BLOCK, &set, NULL);

while (1) {
        sigwait(&set, &sig);
        switch (sig) {
                case SIGINT:
                        break;
                case SIGQUIT:
                        break;
                case SIGTERM:
                        break;
                case SIGALRM:
                        timer_callback(sig);
                        break;        
                default:
                        pthread_exit((void *)-1);
        }
 }
}
- теперь известно, что все падает вот тут:
void window_repaint()
{
    printf("repaint\n");
    XClearArea(display, window, 0, 0, window_width, window_height, 0);


    XFontStruct *font = XLoadQueryFont(display, "10x20");
	if (!font)
	{
		exit(EXIT_FAILURE);
	}


	GC gc = XCreateGC(display, window, 0, NULL);



	XSetFont(display, gc, font->fid);

	char timer_message[100];

	timer_str(timer_message);

	int timer_message_pos_x = window_width / 2 - XTextWidth(font, timer_message, strlen(timer_message)) / 2;
    int timer_message_pos_y = window_height / 2 ;
	XDrawString(display, window, gc, timer_message_pos_x, timer_message_pos_y, timer_message, strlen(timer_message));

	char attention_message[100];
	if (timer_get_message(attention_message))
	{
		int attention_message_pos_x = window_width / 2 - XTextWidth(font, attention_message, strlen(attention_message)) / 2;
		int attention_message_pos_y = window_height / 2 + 30;

		XDrawString(display, window, gc, attention_message_pos_x, attention_message_pos_y, attention_message, strlen(attention_message));
	}

	XFreeGC(display, gc);
}
Вопрос - на чем оно тут может гипотетически падать с interrupt system call, и главное - как это победить?

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

Конечно. И заодно обнаружил, что точная причина моих проблем - метод:

void window_repaint_send()
{
	XExposeEvent expose = { Expose, 0, 1, display, window, 0, 0, window_width, window_height, 0 };
	XSendEvent(display, window, 0, ExposureMask, (XEvent *) &expose);
	XFlush(display);
}
Вызываемый из callback процедуры обработки сигнала SIGALRM в таймере. Он отправляет окну эвент, соответвенно - XSendEvent(display, window, 0, ExposureMask, (XEvent *) &expose); - тут и валится. И мыслей насчет почему -0 у меня пока нет-(

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

XLockDispay и XUnlockDisplay помогли. Благодарю всех учавствовавших-)

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