Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 30.11.2011, 11:39   #1
Osanve
Пользователь
 
Аватар для Osanve
 
Регистрация: 11.12.2010
Сообщений: 50
По умолчанию [C] Многопоточное программирование в Linux

Здравствуйте.

Сначала пробовал такой код:
Код:
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>

int mygetch()
{
  struct termios oldt;
  struct termios newt;
  int ch;
  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~( ICANON | ECHO );
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  ch = getchar();
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  return ch;
}

int main()
{
  int kbd;
  while(1)
  {
    kbd = mygetch();
    switch(kbd)
    {
      case '1':
      {
        printf("AA\n");
        break;
      }
      case '2':
      {
        printf("AC\n");
        break;
      }
      case '3':
      {
        printf("CA\n");
        break;
      }
      case '4':
      {
        printf("CC\n");
        break;
      }
      case '5':
      {
        printf("VM\n");
        break;
      }
      case '0':
      {
        exit(0);
      }
    }
  }
}
Клавиатура обрабатывается нормально.

Теперь перехожу к основному проекту:
Код:
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <gpm.h>

void graph(void);

int callAA()
{
  execl("A_A", NULL);
  _exit(0);
}

int callAC()
{
  execl("A_C", NULL);
  _exit(0);
}

int callCA()
{
  execl("C_A", NULL);
  _exit(0);
}

int callCC()
{
  execl("C_C", NULL);
  _exit(0);
}

int callVM()
{
  execl("VM", NULL);
  _exit(0);
}

int mygetch()
{
  struct termios oldt;
  struct termios newt;
  int ch;
  tcgetattr(STDIN_FILENO, &oldt);
  newt = oldt;
  newt.c_lflag &= ~( ICANON | ECHO );
  tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  ch = getchar();
  tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  return ch;
}

int my_handler(Gpm_Event *event, void *data)
{
  void **mouseChildStack;
  mouseChildStack = (void **)malloc(16384);
  if(event->x >= 103)
  {
    if(event->x <= 114)
    {
      switch(event->y)
      {
        case 4:
        {
          clone(callAA, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
        case 6:
        {
          clone(callAC, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
        case 8:
        {
          clone(callCA, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
        case 10:
        {
          clone(callCC, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
        case 12:
        {
          clone(callVM, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
        case 14:
        {
          exit(0);
        }
      }
    }
  }
  return 0;
}

void *mouseThread(void *arg)
{
  int c;
  Gpm_Connect conn;
  conn.eventMask = GPM_DOWN;
  conn.defaultMask = ~conn.eventMask;
  conn.minMod = 0;
  conn.maxMod = ~0;
  
  Gpm_Open(&conn, 0);
  gpm_handler = my_handler;
  while(c = Gpm_Getc(stdin)){}
  Gpm_Close();
}

void *kbdThread(void *arg)
{
  int kbd;
  void **kbdChildStack;
  kbdChildStack = (void **)malloc(16384);
  while(1)
  {
    kbd = mygetch();
    switch(kbd)
    {
      case '1':
      {
        clone(callAA, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
      case '2':
      {
        clone(callAC, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
      case '3':
      {
        clone(callCA, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
      case '4':
      {
        clone(callCC, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
      case '5':
      {
        clone(callVM, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
      case '0':
      {
        exit(0);
      }
    }
  }
}

int main()
{
  Gpm_Connect conn;
  conn.eventMask = GPM_DOWN;
  conn.defaultMask = ~conn.eventMask;
  conn.minMod = 0;
  conn.maxMod = ~0;
  pthread_t mouseThreadID, kbdThreadID;
  int mouseID, kbdID;
  
  graph();
  mouseID = pthread_create(&mouseThreadID, NULL, mouseThread, NULL);
//  kbdID = pthread_create(&kbdThreadID, NULL, kbdThread, NULL);
//  kbdID = pthread_join(kbdThreadID, NULL);
  mouseID = pthread_join(mouseThreadID, NULL);

  return 0;
}
С закомментированными строками создания потока клавиатуры программа работает нормально. Поток, отвечающий за обработку мыши сбоев не дает. Теперь раскомментируем строчки
Код:
kbdID = pthread_create(&kbdThreadID, NULL, kbdThread, NULL);
kbdID = pthread_join(kbdThreadID, NULL);
и у меня накрывается система ввода-вывода.

В чем может быть проблема?

Заранее спасибо.
Osanve вне форума Ответить с цитированием
Старый 30.11.2011, 11:57   #2
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию

Не уверен, поможет ли...
Попробуй дать время потоку на старт. После создания потока -- команду sleep() на 1 секунду.
Были похожие проблемы с потоками, но, правда, под Линуксом.
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062
Mandrivnyk вне форума Ответить с цитированием
Старый 30.11.2011, 12:05   #3
Osanve
Пользователь
 
Аватар для Osanve
 
Регистрация: 11.12.2010
Сообщений: 50
По умолчанию

Цитата:
Сообщение от Mandrivnyk Посмотреть сообщение
Не уверен, поможет ли...
Попробуй дать время потоку на старт.
Как это сделать?

Цитата:
Сообщение от Mandrivnyk Посмотреть сообщение
После создания потока -- команду sleep() на 1 секунду.
Сделано изначально.

Цитата:
Сообщение от Mandrivnyk Посмотреть сообщение
Были похожие проблемы с потоками, но, правда, под Линуксом.
Именно под линуксом и делаю.
Osanve вне форума Ответить с цитированием
Старый 30.11.2011, 12:56   #4
Mandrivnyk
Software Developer
Участник клуба
 
Аватар для Mandrivnyk
 
Регистрация: 01.03.2011
Сообщений: 1,098
По умолчанию

Цитата:
Как это сделать?
Командой sleep()

Цитата:
Сделано изначально.
Где?

Я имел в виду что-то вроде:

Код:
  mouseID = pthread_create(&mouseThreadID, NULL, mouseThread, NULL);
  sleep(1);
  kbdID = pthread_create(&kbdThreadID, NULL, kbdThread, NULL);
  sleep(1);
  kbdID = pthread_join(kbdThreadID, NULL);
  mouseID = pthread_join(mouseThreadID, NULL);
И еще одно уточнение -- я пользовался boost'овской библиотекой потоков...
Болтовня ничего не стоит. Покажите мне код. (c) Linus Torvalds
Помог ответ? -- Поставьте отзыв.
Выражения особой благодарности в рублевом эквиваленте отправлять сюда --> R269634919062
Mandrivnyk вне форума Ответить с цитированием
Старый 30.11.2011, 13:18   #5
Osanve
Пользователь
 
Аватар для Osanve
 
Регистрация: 11.12.2010
Сообщений: 50
По умолчанию

Сделал таким образом:
Код:
...

void *mouseThread(void *arg)
{
  sleep(1);
  ...
}

void *kbdThread(void *arg)
{
  sleep(1);
  ...
}

int main()
{
  Gpm_Connect conn;
  conn.eventMask = GPM_DOWN;
  conn.defaultMask = ~conn.eventMask;
  conn.minMod = 0;
  conn.maxMod = ~0;
  pthread_t mouseThreadID, kbdThreadID;
  int mouseID, kbdID;
  
  graph();
  mouseID = pthread_create(&mouseThreadID, NULL, mouseThread, NULL);
  sleep(1);
  kbdID = pthread_create(&kbdThreadID, NULL, kbdThread, NULL);
  sleep(1);
  kbdID = pthread_join(kbdThreadID, NULL);
  mouseID = pthread_join(mouseThreadID, NULL);

  return 0;
}
Далее компиляция без ошибок и предупреждений:
Код:
$ gcc ./main.c ./graph.c -D_REENTERANT -I/usr/include/nptl -L/usr/lib/nptl -lpthread -lgpm
Результат такой же.
Osanve вне форума Ответить с цитированием
Старый 01.12.2011, 16:12   #6
Osanve
Пользователь
 
Аватар для Osanve
 
Регистрация: 11.12.2010
Сообщений: 50
По умолчанию

Путем тестов было определено что не вызывается функция clone() из этой части кода (ну и следовательно из аналогичных по клаве):
Код:
      case '1':
      {
        clone(callAA, kbdChildStack, NULL, NULL);
        sleep(1);
        graph();
        break;
      }
При этом абсолютно идентичный вызов от мыши работает:
Код:
        case 4:
        {
          clone(callAA, mouseChildStack, NULL, NULL);
          sleep(1);
          graph();
          break;
        }
В чем проблема никак не могу понять.
Osanve вне форума Ответить с цитированием
Старый 02.12.2011, 12:21   #7
Osanve
Пользователь
 
Аватар для Osanve
 
Регистрация: 11.12.2010
Сообщений: 50
По умолчанию

Исправленный код на поток клавы:
Код:
void *kbdThread(void *arg)
{
  sleep(1);
  int kbd;
  while(1)
  {
    kbd = mygetch();
    switch(kbd)
    {
      case '1':
      {
        int pid;
        pid = fork();
        if(pid < 0)
        {
          printf("fork() going away!\n");
        }
        else
        {
          if(pid == 0)
          {
            execl("A_A", NULL);
            printf("execl() going away\n");
          }
          else
          {
            waitpid(pid, 0, 0);
          }
        }
        sleep(1);
        graph();
        break;
      }
      case '2':
      {
        int pid;
        pid = fork();
        if(pid < 0)
        {
          printf("fork() going away!\n");
        }
        else
        {
          if(pid == 0)
          {
            execl("A_C", NULL);
            printf("execl() going away\n");
          }
          else
          {
            waitpid(pid, 0, 0);
          }
        }
        sleep(1);
        graph();
        break;
      }
      case '3':
      {
        int pid;
        pid = fork();
        if(pid < 0)
        {
          printf("fork() going away!\n");
        }
        else
        {
          if(pid == 0)
          {
            execl("C_A", NULL);
            printf("execl() going away\n");
          }
          else
          {
            waitpid(pid, 0, 0);
          }
        }
        sleep(1);
        graph();
        break;
      }
      case '4':
      {
        int pid;
        pid = fork();
        if(pid < 0)
        {
          printf("fork() going away!\n");
        }
        else
        {
          if(pid == 0)
          {
            execl("C_C", NULL);
            printf("execl() going away\n");
          }
          else
          {
            waitpid(pid, 0, 0);
          }
        }
        sleep(1);
        graph();
        break;
      }
      case '5':
      {
        int pid;
        pid = fork();
        if(pid < 0)
        {
          printf("fork() going away!\n");
        }
        else
        {
          if(pid == 0)
          {
            execl("VM", NULL);
            printf("execl() going away\n");
          }
          else
          {
            waitpid(pid, 0, 0);
          }
        }
        sleep(1);
        graph();
        break;
      }
      case '0':
      {
        exit(0);
      }
    }
  }
}
Теперь все работает.
Osanve вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
многопоточное программирование jul01 Помощь студентам 0 10.06.2011 17:47
Программирование под Linux ji_ji Lazarus, Free Pascal, CodeTyphon 4 12.07.2010 14:00
Linux программирование allaur Фриланс 1 21.12.2009 11:22
многопоточное программирование schnaps Общие вопросы Delphi 0 27.04.2009 19:09
Многопоточное программирование madmax08 Общие вопросы .NET 4 15.07.2008 23:58