The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

форумы  помощь  поиск  регистрация  майллист  ВХОД  слежка  RSS
"Семафоры"
Вариант для распечатки  
Пред. тема | След. тема 
Форумы Программирование под UNIX (Public)
Изначальное сообщение [Проследить за развитием треда]

"Семафоры" 
Сообщение от AKProggy emailИскать по авторуВ закладки on 05-Янв-06, 15:05  (MSK)
Вечер добрый! Большая к Вам просьба объяснить в чем тут суть =)
Имеется следующая простенькая програмка:
-----------------------------------------------------------
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>

sem_t A,B,C,AB; //Semaphores for all details and module
pthread_t pidA, pidB, pidC, pidM,pidEnd; //ID for all developments
int number, wMaked; //Counter of widgets

int sig(int signum) {
/*    pthread_canpcel(pidA);
    pthread_cancel(pidB);
    pthread_cancel(pidC);
    pthread_cancel(pidM);
    pthread_cancel(pidEnd);*/
    printf("A=%d\n",A.sem_count);
    printf("B=%d\n",B.sem_count);
    printf("C=%d\n",C.sem_count);
    exit();
}

//Make A detail for 1
void* makeA(void* t)
{
    for(;;) {
    sleep(1);
    sem_post(&A);
    write(1,"One more A\n",11);
    }
}

//Make B detail for 2
void* makeB(void* t)
{
    for(;;) {sleep(2);
    sem_post(&B);
    write(1,"One more B\n",11); }
}

void* makeC(void* t)
{
    for(;;)
    {
        sleep(3);
        sem_post(&C); //Make C detail for 3
        write(1,"One more C\n",11);
    }
}

void* makeModule(void* t)
{
    for(;;)
    {
    sem_wait(&A);
    sem_wait(&B); //Waiting for A and B and then make C
    sem_post(&AB);
    write(1,"One more module!\n",17);
    }
}

//Collect all details
void* Collect(void* t)
{
    for(;;)
    {
        sem_wait(&AB); //Wait for all details
        sem_wait(&C); //Wait for C
        write(1,"Widget already made!\n",21); //Report about widget
        wMaked++; //Increment widget's counter
    }
}

void main() {
    signal(SIGINT,sig);
    sem_init(&A,0,0); sem_init(&B,0,0); sem_init(&C,0,0); //Init of semaphores
    pthread_create(&pidA, NULL, &makeA,NULL); //Run A development
    pthread_create(&pidB, NULL, &makeB,NULL); //Run B development
    pthread_create(&pidC, NULL, &makeC,NULL); //Run C development
    pthread_create(&pidM, NULL, &makeModule,NULL); //Run M development
    pthread_create(&pidEnd, NULL, &Collect,NULL); //Run Collect development
    pthread_exit(NULL);
}
-----------------------------------------------------------
Весьма примитивная - иммитатор фабрики, детали A,B и С создаются параллельно, и соответственно собираются в целое, когда по одной A, B и С уже создано... Программа останавливается по ctrl+C и, как написано в функции sig(int signum) должна выводить оставшиеся, неиспользованные детали... она вроде-как это делает, но почему-то при проверке фраза "One more A" встречается например 4 раза, "Widget already made" 2 раза, т.е по идее A должно остаться 2 штуки... а пишет например 3... или 1 итд.
В чем проблема и как это исправить? Заранее спасибо!

  Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

 Оглавление

  • Семафоры, Wulf, 18:49 , 05-Янв-06, (1)  
    • Семафоры, AKProggy, 05:34 , 09-Янв-06, (3)  
    • Семафоры, AKProggy, 14:16 , 10-Янв-06, (5)  
      • Семафоры, Wulf, 17:50 , 10-Янв-06, (6)  
        • Семафоры, AKProggy, 19:02 , 10-Янв-06, (7)  
          • Семафоры, Wulf, 22:38 , 10-Янв-06, (8)  
  • Семафоры, Hehe, 13:07 , 06-Янв-06, (2)  
    • Семафоры, DeadMustdie, 12:00 , 09-Янв-06, (4)  
      • Семафоры, Hehe, 11:33 , 11-Янв-06, (9)  
        • Семафоры, DeadMustdie, 13:10 , 11-Янв-06, (10)  

Сообщения по теме [Сортировка по времени, UBB]

1. "Семафоры" 
Сообщение от Wulf Искать по авторуВ закладки on 05-Янв-06, 18:49  (MSK)
>Вечер добрый! Большая к Вам просьба объяснить в чем тут суть =)
>
>Имеется следующая простенькая програмка:
>В чем проблема и как это исправить? Заранее спасибо!

Студент-троечник сдает курсовую? :-)

В чем проблема - не скажу из вредности, а исправить это элементарно:

в void* makeModule(void* t) - поменять местами строки sem_wait(&A); и sem_wait(&B);
в void* Collect(void* t)- соответственно sem_wait(&AB); и sem_wait(&C);

PS: в данном виде программа нерабочая - как минимум, отсутствует инициализация семафора AB
PPS: Еще необходимо помнить, что часть деталей A и B находится в виде модулей AB

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

3. "Семафоры" 
Сообщение от AKProggy emailИскать по авторуВ закладки on 09-Янв-06, 05:34  (MSK)
>Студент-троечник сдает курсовую? :-)
Нет, студент-троечник получает зачет =)

>в void* makeModule(void* t) - поменять местами строки sem_wait(&A); и sem_wait(&B);
>в void* Collect(void* t)- соответственно sem_wait(&AB); и sem_wait(&C);
Странно, мне казалось от перестановки слагаемых сумма не меняется... видимо это работает как-то иначе... объясните все же пожалуйста! =)


  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

5. "Семафоры" 
Сообщение от AKProggy emailИскать по авторуВ закладки on 10-Янв-06, 14:16  (MSK)
>В чем проблема - не скажу из вредности, а исправить это элементарно:
>в void* makeModule(void* t) - поменять местами строки sem_wait(&A); и sem_wait(&B);
>в void* Collect(void* t)- соответственно sem_wait(&AB); и sem_wait(&C);
Объясните пожалуйста, как сделать так, чтобы порядок был не важен...
Ооооочень нужно - зачет.... =(

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

6. "Семафоры" 
Сообщение от Wulf Искать по авторуВ закладки on 10-Янв-06, 17:50  (MSK)
>>В чем проблема - не скажу из вредности, а исправить это элементарно:
>>в void* makeModule(void* t) - поменять местами строки sem_wait(&A); и sem_wait(&B);
>>в void* Collect(void* t)- соответственно sem_wait(&AB); и sem_wait(&C);
>Объясните пожалуйста, как сделать так, чтобы порядок был не важен...
Чтобы порядок был неважен, Вам нужно добиться атомарного с точки зрения выводящих результат процедур, изменения комлектов счетчиков по всей програмульке. Если это делать по-честному, нужно переписывать. Грязный хак для Вашего конкретного случая я уже привел. Проблема программы в изначальном виде - гарантированная рассинхронизация изменения значений семафоров со стороны строк printf("A=%d\n",A.sem_count);.
В треде с makeModule исполнение идет пачкой
sem_wait(&B);
sem_post(&AB);
sem_wait(&A);
- именно в такой последовательности, т.к. последовательность подачи деталей такова, что тред будет все время висеть на семафоре &B. посему и набегает лишний sem_wait(&A);
в треде с Collect - ситуация аналогична.


  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

7. "Семафоры" 
Сообщение от AKProggy emailИскать по авторуВ закладки on 10-Янв-06, 19:02  (MSK)
>Чтобы порядок был неважен, Вам нужно добиться атомарного с точки зрения выводящих
>результат процедур, изменения комлектов счетчиков по всей програмульке. Если это делать
>по-честному, нужно переписывать. Грязный хак для Вашего конкретного случая я уже
>привел. Проблема программы в изначальном виде - гарантированная рассинхронизация изменения значений
>семафоров со стороны строк printf("A=%d\n",A.sem_count);.
>В треде с makeModule исполнение идет пачкой
>sem_wait(&B);
>sem_post(&AB);
>sem_wait(&A);
>- именно в такой последовательности, т.к. последовательность подачи деталей такова, что тред
>будет все время висеть на семафоре &B. посему и набегает лишний
>sem_wait(&A);
>в треде с Collect - ситуация аналогична.
А как требуется переписать? Косяк в том, что в makeModule входим допустим, делаем sem_wait(&A), затем начинает sem_wait(&B) и по ctrl+C падает... в итоге sem_wait уменьшил значение A на единицу, но модуль не создал... И в итоге теряется... как сделать, чтобы порядок был не важен? Флаговые переменные заводить нельзя ибо ctrl+c по идее может прервать между sem_post и изменением флага...
Объясните все-же пожалуйста, как изменить прогу, чтобы было корректно?

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

8. "Семафоры" 
Сообщение от Wulf Искать по авторуВ закладки on 10-Янв-06, 22:38  (MSK)
>Объясните все-же пожалуйста, как изменить прогу, чтобы было корректно?
Вообще, я не являюсь знатоком IPC, но могу предложить следующий метод:
1. Для счетчиков вместо семафоров используются глобальные переменные, закрытые мутексом(мутексами).
2. Для коммуникации между тредами используется posix messaging: 1-я очередь makeModule() "слушает" приход деталей от MakeA() и МакеB(), 2-я - Collect() собирает сообщения ов AB и C.
3. Обработчик SIGINT _НЕ_ производит вывод/выход, а устанавливает флаг выхода/посылает сообщения о выходе.
4. Треды производят обработку информации из п.3. и завершаются _САМОСТОЯТЕЛЬНО_.
5. Вывод числа деталей производится в main() по окончанию работы всех тредов.
Вероятно, существуют и более простые/красивые/быстрые варианты, но и такой должен работать корректно.
  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

2. "Семафоры" 
Сообщение от Hehe Искать по авторуВ закладки on 06-Янв-06, 13:07  (MSK)
Остались же еще маньяки, пишушие на Си с использованием голого API :)
  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

4. "Семафоры" 
Сообщение от DeadMustdie emailИскать по авторуВ закладки(??) on 09-Янв-06, 12:00  (MSK)
>Остались же еще маньяки, пишушие на Си с использованием голого API :)

Смотря где применяться будет. Если нужна мелкая везде собирающаяся
программулина, стоит потратить на неё дополнительные 30 минут и
не таскать вместе с ней горы компиляторов/рантаймов/просто библиотек.
Как Вам, например, такое (собирается везде и везде работает, никаких
доп. плясок с бубном с настройками сетевых сервисов для пересылки
файлика через сеть):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifdef WIN32

# include <winsock2.h>
# include <windows.h>

#define sleep(n) SleepEx((n)*1000, FALSE);
typedef int ssize_t;

#else

# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <netdb.h>
# include <unistd.h>
# include <strings.h>

#define closesocket close
extern int h_errno;

#endif


#define BUF_SIZE 32768

static int do_resolve_addr(const char* host, struct sockaddr_in* addr_in)
{
  struct hostent *hp = NULL;
  
  do {
    errno = 0;
    hp = gethostbyname(host);
  } while ( hp==NULL && (h_errno==TRY_AGAIN || errno==EINTR) );
  
  if ( hp==NULL )
    return -1;
  
  memcpy(&addr_in->sin_addr, *(hp->h_addr_list),
         sizeof(addr_in->sin_addr.s_addr));
  
  return 0;
}

static int do_make_address(const char* addr, struct sockaddr_in* addr_in)
{
  char *new_host, *new_port;
  
  new_host = strdup(addr);
  new_port = strstr(new_host, ":");
  if ( new_port )
    {
      *new_port = '\0';
      new_port++;
    }
  else
    new_port = "9999";
  
  addr_in->sin_family = AF_INET;
  addr_in->sin_port = htons((unsigned short)atoi(new_port));
  addr_in->sin_addr.s_addr = inet_addr(new_host);
  
  if ( addr_in->sin_addr.s_addr == -1)
    if ( do_resolve_addr(new_host, addr_in) < 0 ) {
      fprintf(stderr, "netstream: cannot resolve address: %s\n", strerror(errno));
      free(new_host);
      return -1;
    }
  free(new_host);
  return 0;
}


/* ------------------------------------------------------------ */
static int do_send(const char* addr, FILE* f)
{
  char buf[BUF_SIZE];
  struct sockaddr_in addr_in;
  int sock, cnc;
  size_t nbytes;
  
  if ( do_make_address(addr, &addr_in) == -1 )
    return 1;
  
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if ( sock==-1 ) {
    fprintf(stderr, "netstream: cannot create socket: %s\n", strerror(errno));
    return 1;
  }
  
  if ( bind(sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) == -1 ) {
    fprintf(stderr, "netstream: cannot bind socket: %s\n", strerror(errno));
    shutdown(sock, 2);
    closesocket(sock);
    return 1;
  }
  
  if ( listen(sock, 1) == -1 ) {
    fprintf(stderr, "netstream: cannot listen: %s\n", strerror(errno));
    shutdown(sock, 2);
    closesocket(sock);
    return 1;
  }
  
  do {
    cnc = accept(sock, NULL, NULL);
    if ( cnc<0 )
      sleep(1);
  } while (cnc<0);
  
  shutdown(sock, 2);
  closesocket(sock); sock = -1;
  
  while ( !ferror(f) && !feof(f) ) {
    nbytes = fread(buf, 1, sizeof(buf), f);
    if ( nbytes<1 )
      continue;
    if ( send(cnc, buf, nbytes, 0) == -1 ) {
      fprintf(stderr, "netstream: cannot send: %s\n", strerror(errno));
      shutdown(cnc, 2);
      closesocket(cnc);
      return 2;
    }
  }
  
  if ( ferror(f) ) {
    fprintf(stderr, "netstream: file read error: %s\n", strerror(errno));
    return 2;
  }
  
  shutdown(cnc, 2);
  closesocket(cnc);
  return 0;
}

/* ------------------------------------------------------------ */
static int do_recv(const char* addr, FILE* f)
{
  char buf[BUF_SIZE];
  struct sockaddr_in addr_in;
  int sock;
  ssize_t nbytes;
  
  if ( do_make_address(addr, &addr_in) == -1 )
    return 1;
  
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if ( sock==-1 ) {
    fprintf(stderr, "netstream: cannot create socket: %s\n", strerror(errno));
    return 1;
  }
  
  if (connect(sock, (struct sockaddr*)&addr_in, sizeof(addr_in)) == -1) {
    fprintf(stderr, "netstream: unable to connect: %s\n", strerror(errno));
    shutdown(sock, 2);
    closesocket(sock);
    return 1;
  }
  
  for (;;) {
    nbytes = recv(sock, buf, sizeof(buf), 0);
    if ( nbytes==0 )
      break;
    if ( nbytes < 0 ) {
      fprintf(stderr, "netstream: unable to recv: %s\n", strerror(errno));
      shutdown(sock, 2);
      closesocket(sock);
      return 2;
    }
    if (fwrite(buf, 1, nbytes, f) != (size_t)nbytes) {
      fprintf(stderr, "netstream: file write failed: %s\n", strerror(errno));
      shutdown(sock, 2);
      closesocket(sock);
      return 2;
    }
  }
  
  shutdown(sock, 2);
  closesocket(sock);
  return 0;
}


/* ------------------------------------------------------------ */
static void usage_and_die()
{
  fprintf(stderr, "USAGE:\n\tnetstream {send|receive} address [filename]\n");
  exit(3);
}

int main(int argc, char* argv[])
{
  int ret = 0;
  FILE* f = NULL;
  
#ifdef WIN32
  WORD wVersionRequested;
  WSADATA data;
  
  wVersionRequested = MAKEWORD(1, 1);
  WSAStartup(wVersionRequested, &data);
#endif
  
  if ( argc!=3 && argc!=4 )
    usage_and_die();
  
  switch ( *argv[1] ) {
  case 's': case 'S':
    f = stdin;
    if ( argc==4 )
      f = fopen(argv[3], "rb");
    break;
  case 'r': case 'R':
    f = stdout;
    if ( argc==4 )
      f = fopen(argv[3], "wb");
    break;
  default:
    usage_and_die();
  }
  
  if ( argc==4 && f==NULL ) {
    fprintf(stderr, "netstream: cannot open '%s': %s\n", argv[3], strerror(errno));
    return 2;
  }
  
  switch ( *argv[1] ) {
  case 's': case 'S':
    ret = do_send(argv[2], f);
    break;
  case 'r': case 'R':
    ret = do_recv(argv[2], f);
    break;
  }
  
  if ( f!=stdin || f!=stdout )
    fclose(f);
  
  return ret;
}

/* End Of File */

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

9. "Семафоры" 
Сообщение от Hehe Искать по авторуВ закладки on 11-Янв-06, 11:33  (MSK)
>>Остались же еще маньяки, пишушие на Си с использованием голого API :)
>
>Смотря где применяться будет. Если нужна мелкая везде собирающаяся
>программулина, стоит потратить на неё дополнительные 30 минут и
>не таскать вместе с ней горы компиляторов/рантаймов/просто библиотек.
>Как Вам, например, такое (собирается везде и везде работает, никаких
>доп. плясок с бубном с настройками сетевых сервисов для пересылки
>файлика через сеть):
>

Да, честно сказать, никак. Я бы наверное уволился, но такой код сопровождать не стал. Навевает грустные мысли о 20 веке.

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх

10. "Семафоры" 
Сообщение от DeadMustdie emailИскать по авторуВ закладки(??) on 11-Янв-06, 13:10  (MSK)
>Да, честно сказать, никак. Я бы наверное уволился, но такой код
>сопровождать не стал. Навевает грустные мысли о 20 веке.

Без обид, но скорее - о Вашей квалификации. Ибо код простой и понятный до безобразия.

  Удалить Правка | Высказать мнение | Ответить | Рекомендовать в FAQ | Cообщить модератору | Наверх


Архив | Удалить

Индекс форумов | Темы | Пред. тема | След. тема
Оцените тред (1=ужас, 5=супер)? [ 1 | 2 | 3 | 4 | 5 ]




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру