Форум русскоязычного сообщества Ubuntu


Считаете, что Ubuntu недостаточно дружелюбна к новичкам?
Помогите создать новое Руководство для новичков!

Автор Тема: Вопрос по потокам[C]  (Прочитано 681 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн CynicRus

  • Автор темы
  • Любитель
  • *
  • Сообщений: 78
    • Просмотр профиля
Вопрос по потокам[C]
« : 14 Март 2012, 13:47:22 »
Доброго времени суток, господа. Собственно - вопрос в следующем. Имеются 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 и состоят из попыток адаптировать писание Рочкинда к своей ситуации.
"Only two things are infinite, the universe and human stupidity... and I'm not sure about the universe."  -- Albert Einstein

Оффлайн Yurror

  • Старожил
  • *
  • Сообщений: 1966
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #1 : 15 Март 2012, 06:13:42 »
Это избыточно.

Но можно и так если сильно хочется. Будем считать это обучением по многопоточности.

С потоками работают с помощью библиотеки pthread документации по ней вагон и маленькая тележка.
тут где-то на форуме рекламировали книжку Стевенса "UNIX. Взаимодействие" процессов или что-то типа того.

сделай один поток обрабатывающий события X11
http://dfe.karelia.ru/koi/posob/X/example1.htm

а второй будет ждать unix-сигналов (man sigwait) среди которых будет и SIGALRM
http://www.regatta.cs.msu.su/doc/usr/share/man/info/ru_RU/a_doc_lib/aixprggd/genprogc/signal_mgmt.htm

Напиши 1 функцию перерисовки экрана. Вызывай её из двух потоков. Или по событию перерисовки окна (если оно будет перекрыто другими и снова отображено) или по таймеру. Естественно в самой функции перерисовки окна надо вставить mutex для того чтобы защититься от одновременного вызова процедуры из двух разных потоков.

Ну по таймеру еще перед перерисовкой окна не забывай обновить строчку с текущим временем.

Как-то так.

Оффлайн CynicRus

  • Автор темы
  • Любитель
  • *
  • Сообщений: 78
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #2 : 15 Март 2012, 12:27:10 »
И так...загоняю таймер в поток:void* initTimer(void* arg)
{
    timer_init();
    printf("Timer Thread\n");
}

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();
}
*****

pthread_t tthread;


int tterror,arg;

if( tterror = pthread_create(&tthread,NULL,initTimer,(void*)arg)) {
                        printf("TThread creation failed: %d\n", tterror);
}
*****
Когда окно в основном потоке, таймер в дополнительном - замечательно все.
Затем, вывожу окно в другой поток. И на уровне window_loop - получаю Interrupted system call.
Код window_loop() с необходимыми методами:
void window_loop()
{
int ret;
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;
}
}
}
}

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);
}

void window_repaint()
{

    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);
}
Догадываюсь, что проблема в недрах window_loop, при обращении таймера к window_repaint_send и соответственным вызовом window_repaint. Пробовал через mutex заблокировать repaint, и вызывать его из таймера по готовности, но как-то это не принесло дивидендов. Видимо я как-то неправильно обрабатываю евент Expose, пробовал loop вынести в отдельный поток - получил segfault. Вообщем - я что-то делаю определенно неправильно, но что - понять не могу.

Пользователь решил продолжить мысль 15 Март 2012, 15:55:49:
Прикрутил поток обработки сигналов,
void* checkSignal()
{
sigset_t set;
int sig;

sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGALRM);
//sigthreadmask(SIG_BLOCK, &set, NULL);
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, и главное - как это победить?
« Последнее редактирование: 15 Март 2012, 15:55:49 от CynicRus »
"Only two things are infinite, the universe and human stupidity... and I'm not sure about the universe."  -- Albert Einstein

Оффлайн Yurror

  • Старожил
  • *
  • Сообщений: 1966
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #3 : 15 Март 2012, 17:04:41 »
сигналы прерывают системные вызовы
они возвращают ошибку EINTR
где-то эта ошибка обрабатывается странным образом. вызывает выход из приложения вместо простого повторения системного вызова

Оффлайн CynicRus

  • Автор темы
  • Любитель
  • *
  • Сообщений: 78
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #4 : 16 Март 2012, 10:35:17 »
XLockDispay и XUnlockDisplay помогли.
"Only two things are infinite, the universe and human stupidity... and I'm not sure about the universe."  -- Albert Einstein

Оффлайн S_F_H

  • Участник
  • *
  • Сообщений: 129
  • Да будет crossplatform!
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #5 : 17 Март 2012, 20:30:42 »
а что мешает использовать каналы?

Оффлайн Yurror

  • Старожил
  • *
  • Сообщений: 1966
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #6 : 18 Март 2012, 08:08:23 »
CynicRus,
я же сразу написал про блокировку одновременного вызова процедуры перерисовки из двух потоков!

S_F_H,
НАФИГА? Куда ты их присобачишь? пихаем везде то что знаем на остальное пофиг?

Оффлайн CynicRus

  • Автор темы
  • Любитель
  • *
  • Сообщений: 78
    • Просмотр профиля
Re: Вопрос по потокам[C]
« Ответ #7 : 18 Март 2012, 10:52:30 »
CynicRus,
я же сразу написал про блокировку одновременного вызова процедуры перерисовки из двух потоков!

Замыленый взгляд - не всегда замечает очевидное-)
"Only two things are infinite, the universe and human stupidity... and I'm not sure about the universe."  -- Albert Einstein

 

Страница сгенерирована за 0.082 секунд. Запросов: 25.