SoftCraft
разноликое программирование

Top.Mail.Ru

P. S. Размерность программного пространства...

© Беляев М.В.

(Новосибирск, НГПУ)

belyaev@e-mail.ru

В архиве лежит упакованная версия статьи (около 4 кб)

Как следует из заголовка, настоящая заметка является постскриптумом к предыдущему материалу. Потребность в постскриптуме возникла в связи с тем, что мной была допущена ошибка. А именно, неверно утверждение: "если одновременно поменять 0 на обоих входах на 1, то триггер перейдет в одно из двух основных состояний ... непредсказуемым образом". В действительности у некоторых (полностью симметричных) триггеров эта манипуляция может вызвать генерацию. Следовательно и мой вывод о невозможности генерации в системе 2"И"-"НЕ" тоже неверен.

Деструктивная сила одновременности

Тем не менее, на моих основных выводах эта досадная оплошность не отразилась. Мое утверждение: "если одновременные события взаимодействуют, то для нормального функционирования системы такая ситуация должна быть исключена", - даже получило дополнительное подтверждение. Одновременное наступление взаимодействующих событий не приводит ни к чему кроме неприятностей. Для триггера большей неприятности, чем генерация не существует. Мой позитивный подсознательный настрой сыграл со мной злую шутку - заставил объявить невозможным нежелательный исход. Триггер казался таким совершенным прибором, но умельцы нашли таки способ его испортить. К этому ведет двухходовая комбинация:

  1. перевести триггер в запрещенное состояние (0 на оба входа)
  2. ОДНОВРЕМЕННО на оба входа подать 1
Вентили одновременно изменяют свое состояние и им это приходится делать раз за разом. А мы попиваем кофе и радуемся достигнутому результату.

В программах представленных в предыдущем материале не было возможности установить значения входов триггеров ОДНОВРЕМЕННО. Внеся соответстующие изменения в операции ввода, и добавив две переменные и несколько строк кода, мы получаем программу полностью моделирующую злополучный триггер. И хотя параллельность в моделируемой системе исключить невозможно (из-за строгой одновременности), но она прекрасно эмулируется на "двумерном" Си. Полный листинг программы с подробными комментариями вы можете найти в Приложении .

Таким образом утверждение В. Любченко: "Если все выполнено корректно, то в параллельной среде, имеющей трехмерные свойства, триггер при определенных условиях будет входить в режим генерации, в двумерной же - нет", - по-прежнему остается неверным.

Приложение.

/*-------------------------------------------------
 Программная модель "триггера"
 - двух перекрестно соединенных логических вентилей
 с возможностью одновременной установки входов
 Copyright (c) М.В. Беляев, 2001

 Для получения генерации в системе 2 "И"-"НЕ" достаточно 
 любым способом установить оба входа в 0 (нажав 1 и 3, или 5) 
 и затем ОДНОВРЕМЕННО на оба входа подать 1 (нажать 8).
 ------------------------------------------------- */

#include <stdio.h>
#include <conio.h>

/* возможные типы вентилей*/
typedef  enum
  {and_not, or_not, and_, or_} v_types; 

v_types vs_type, vr_type; /* типы вентилей S и R    */

int S, R;               /* входы и                */
int Q, P;              /* выходы "триггера"      */
int same_time;        /* флаг одновремен. ввода */
int QR;              /*  вход Q вентиля R      */

int not_end=1;     /* управляет завершением  */

/*------------------------------------------------- */

v_types SetVType(char *prompt) /* задание типа вентиля */
{
 printf("Choose %s ventil type:\n", prompt);
 for(;;)
    {
     puts("0 - and_not, 1 - or_not, 2 - and_, 3 - or_");
     switch(getch())
           {
            case '0': return and_not;
            case '1': return or_not;
            case '2': return and_;
            case '3': return or_;
           }
    }
}

/*------------------------------------------------- */

void CheckKey()       /* управление входами "триггера" */
{
 if(kbhit())        /* была ли нажата клавиша?       */
   {
    switch(getch())
          { /* установка входов "триггера"*/
           /* последовательная           */
           case '1':S=0; puts("S=0"); same_time=0; break; 
           case '2':S=1; puts("S=1"); same_time=0; break; 
           case '3':R=0; puts("R=0"); same_time=0; break; 
           case '4':R=1; puts("R=1"); same_time=0; break;
           /* одновременная          */
           case '5':S=0; R=0; puts("S=0 R=0"); same_time=1;break;
           case '6':S=1; R=0; puts("S=1 R=0"); same_time=1;break;
           case '7':S=0; R=1; puts("S=0 R=1"); same_time=1;break;
           case '8':S=1; R=1; puts("S=1 R=1"); same_time=1;break;
           case '\033' : not_end = 0;  /* ESC - конец работы */
          }
   }
}

/*------------------------------------------------- */

void print() /* вывод на косоль состояния выходов */
{
 printf(" Q= %1d P= %1d\n", QR, P);
}

/*------------------------------------------------- */

int op(v_types v_type, int x, int y) /* логическая операция вентиля */
{
 switch (v_type)
        {
         case  and_not: return !(x && y);
         case  or_not : return !(x || y);
         case  and_   : return  (x && y);
         case  or_    : return  (x || y);
        }
}

 /*------------------------------------------------- */
/* действие на переходе S -> R                      */
void VS()       
{
 int x; 
 CheckKey();  /* если нажали нужную клавишу - изменить S или R 
                 или сразу S и R */
 x = op(vs_type, S, P);
 if(x != Q)
   {
    Q=x;                   /* вентиль S на выходе дает Q  */
    if(!same_time) print();          /* вывод на консоль */
   }
 if(!same_time) QR = Q;  /*   значение QR обновляется  */
}

 /*------------------------------------------------- */
/* действие на переходе R -> S                      */
void VR()       
{
 int x;
 if(same_time)  /* если флаг одновременности установлен*/
   {
    x = op(vr_type, QR, R); /* используется выход QR    */
                            /* (предыдущее состояние)   */
    QR = Q;                 /*  значение QR обновляется */
   }
 else x = op(vr_type, Q, R);/* иначе используется выход Q */
 if(x != P)
   {
    P=x;     /* вентиль R на выходе дает P */
    print();/* вывод на консоль           */
   }
 else same_time=0;  
}

/*------------------------------------------------- */

int main()
{
 vs_type=SetVType("S");      /* задать тип вентиля S */
 printf("S= %1d \n", vs_type);

 vr_type=SetVType("R");   /* задать тип вентиля R  */
 printf("R= %1d \n", vr_type);

 /* подсказка - как управлять "триггером"       */   
 puts("\nPress key to change any trigger enter:");
 puts("1 - S=0; 2 - S=1; ");
 puts("3 - R=0; 4 - R=1\n");
 puts("5 - S=0,R=0; 6 - S=1,R=0; ");
 puts("7 - S=0,R=1; 8 - S=1,R=1\n");

 puts("Now press any key to start");
 puts("Press ESC to stop\n");
 getch();

 while(not_end)        /*     пока не нажали ESC           */
      {
       VS();         /*  S и R работают по очереди       */
       VR();        /*   - это имитация параллельности! */
      }

 return 0;
}

/*------------------------------------------------- */