Параллельное выполнение объектных действий C++

К примеру, у вас есть несколько объектов одного типа. У каждого есть своя задача/программа, и вам нужно параллельно их обрабатывать. В этом случае вам нужно некое подобие многозадачности.

Для простоты, представьте, у вас на столе лежит яблоко и, вдруг, оно начитает летать в воздухе по синусу; рядом с вами лежит калькулятор, который вываливает на экран всякую чепухню; а на полке лежит карандаш, который просто лежит. 🙂 И вы творец этого мира, вам нужно параллельно руководить всеми объектами.

Либо другой пример — фейерверк. Ведь, запускается не одна ракета, а несколько. И вот они взрываются, все по-разному, затем из них вырывается еще один снаряд и т.д. Вам нужно на ходу создавать/изменять/удалять объекты.

Давайте создадим структуру одного из объектов:

1
2
3
4
5
6
struct Object {
   int x;
   int y;
   unsigned char var[3];
   unsigned char type;
}

Для удобства манипуляции лучше динамически выделять под объекты память. Если объектов ~20шт, то нужно где-то хранить указатели на них. Нам нужен стек: (max=100)

1
struct Object *pointerObj[100];

Перейдем к функции создания объектов. Так как каждый объект должен выполнять свою задачу, ему нужно указать какую. Пусть будет 3типа задачи:

  1. Изменение координат.
  2. Генерация случайных чисел и запись их в массив var.
  3. Выполнять *ничего*.

Функция будет принимать 3 аргумента: координаты и тип задачи:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void createObjects(int x, int y, unsigned char type) {
   uint8_t count = 0;
   while(pointerObj[count]!=NULL) ++count; //Ищем свободное место в стеке
 
   pointerObj[count] = (struct Object*)  malloc(sizeof(struct Object)); //Выделяем память под объект
   pointerObj[count]->type = type; //Присваиваем тип
 
   switch(type) {
      case 1: //Параметры для Задача 1
         pointerObj[count]->x = 0;
         pointerObj[count]->y = 0;
      break;
 
      case 2: //…Задача 2
         pointerObj[count]->var[0] = 0;
         pointerObj[count]->var[1] = 0;
         pointerObj[count]->var[2] = 0;
      break;
 
      case 3: //…Задача 3
         asm("nop"); //Ничего
      break;
    }
}

Естественно, если мы можем создавать объекты, то нужна функция удаления объектов. У функции будет 1 аргумент — номер объекта в стеке. Конечно, можно организовать поиск по координатам и удалять по ним, но пока мы это делать не будем.

1
2
3
4
5
6
void removeObjects(uint8_t count) {
   if (pointerObj[count]!=NULL) {
      free(pointerObj[count]);
      pointerObj[count] = NULL;
   }
}

Да. Мы чуть-чуть не забыли о функции инициализации. А она будет совсем простая. Ее задача — обнулить стек.

1
2
3
void initObjects() {
   for (uint8_t i=0; i<100; ++i) pointerObj[i] = NULL;
}

Теперь давайте перейдем к самому обработчику объектов. Он должен «пробегать» по всему стеку, определять тип задачи объекта и собственно, говоря, выполнять сами задачи.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void actionsObjects() {
  uint8_t count = 0;
  while(count<100) { //Размер стека = 100
  if (pointerObj[count]!=NULL) {
   switch(pointerObj[count]->type) {
      case 1:
          pointerObj[count]->x += rand() % 8 - 16; //Изменяем координаты
          pointerObj[count]->y--;
      break;
 
      case 2:
          pointerObj[count]->var[0] = rand() % 256; //Генерируем чепухню в переменные
          pointerObj[count]->var[1] = rand() % 256;
          pointerObj[count]->var[2] = rand() % 256;
      break;
 
      case 3:
          asm("nop"); //Ничего не делаем
      break;
   }
  }
  ++count;
  }
}

Примечание: использование delay, sleep и прочего, тормозящего программу на N секунд — строго запрещается!
Вот и вся система готова, но нам последующая обработка и, возможно, вывод данных. Общая структура подпрограммы обработки стека вглядит так:

  • Открытие стека
  • Сканирование стека с условием, что ячейка стека не пуста
  • Открытие объекта из ячейки стека
  • Действия с объектом
  • Закрытие объекта из ячейки стека
  • Закрытие стека

…ну или более «человекопонятно» на C++:

1
2
3
4
5
6
7
8
9
10
11
void abrakadabra() {
   uint8_t count = 0;
   while(count<100) {
      if (pointerObj[count]!=NULL) {
         //-------
         //Действия с объектом
         //-------
      }
   ++count;
   }
}

Также хотел упомянуть, что если стек > 100, то, естественно, нужно поменять тип переменной count на uint16_t/uint32_t/uint64_t/uint65536_t. Все это за-за моей чрезмерной оптимизации и экономии.  🙄

Пример использования: (тот же, что и в предыдущих статьях :))

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

Вы можите оставить комментарий, или поставить трэкбек со своего сайта.

Написать комментарий

XHTML: Вы можете использовать эти теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Bug Report
Локализовано: шаблоны Wordpress