Esate.ru

c# + TaoFramework вопрос про работу с потоками.

Всем доброе утро, скажите, почему при зацикливании какого-либо куска кода, ответственного за отрисовку изображение не выводится на экран ? Вот, во всех уроках используется таймер, который в некоторые промежутки времени вызывает функцию отрисовки и это работает. Но , если зациклить эту же функцию и стопить поток , например, Thred.Sleep(TimeSpan.FromMiliceconds(300)), то работать не будет. Почему так происходит ? Вопрос возник потому, что почему-то основное окно зависает, если выполняются какие-либо другие потоки, хотя все функции OpenGL вызываются из одного ( главного) потока. В следующем коде так и происходит, и почему-то потоки "самоубиваются" в процессе. Уже 3 дня не могу понять почему. Вообще, задание такое : есть n квадратов , для каждого квадрата свой поток. Квадраты двигаются в некотором направлении. При столкновении один из квадратов-потоков убивается, другой увеличивается в размере.

Изначально написал так, что каждый квадрат это объект, который может просчитывать свою позицию и отрисовывать себя в нужном месте. Не заработало. Как понял, все openGL функции должны использоваться в том потоке, где был определен контекст рендеринга. Переделал отрисовку в основном потоке. Все равно не заработало, причем странно то, что даже овно приложения не создавалось. В общем, привожу ниже последний вариант, он работате пару итераций а потом окно виснет и почему-то потоки убиваются. . . уже не знаю что с этим делать =((( Вообще можно ли Tao использовать в многопточном приложении ? Скорее всего это я где-то ошибся. . .

/*http://esate.ru, SomeGreatMan*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using Tao.FreeGlut;
using Tao.OpenGl;
using Tao.Platform.Windows;


namespace SAS6
{
   public partial class Form1 : Form
   {
      public Form1()
      {
        InitializeComponent();
        AnT.InitializeContexts();
      }

      // для генерации случайных квадратов
      static Random Rand = new Random();
      
      // количесвто оздаваемых квадратов ( потоков)
      const int MAXSquares = 10;

      static EventWaitHandle wh = new AutoResetEvent(false);

      //  static EventWaitHandle wh1 = new ManualResetEvent(false);

      // для хранения количества потоков, выпонивших просчет ( 1 итерацию)
      static volatile int counter;
      
      static object locker = new object();

      static object lockerforsum = new object();

      // коэффициенты для визуадизации квадрата
      private double a, b, c, Coef;
      
      // матрица, хранящая данные об кажлом квадрате
      private static double[,] ParamsArray; 
      //  k - номер квадрата 
      //  [k,0] = IsAlive
      //  [к,1] = radius
      //  [k,2] = x position
      //  [k,3] = y position

      int NumberOfAlive;

      private void Admin()
      {
                
         // while (true)
        {
           // Thread.Sleep(TimeSpan.FromMilliseconds(200));
                    
           // отрисовываем текущий кадр, по полученным данным
           
           //очищаем экран
           Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);

           // выводим каждый квадрат, в соответствии с характеристиками

           lock (locker)
           {
              for (int i = 0; i < MAXSquares; i++)
              {
                if (ParamsArray[i, 0] == 1.0)
                {

                   // вычисляем параметры, необходимые для
                   //визуализации
                   Coef = ParamsArray[i, 1] / 1.4;
                   a = ParamsArray[i, 2] / 800;
                   b = ParamsArray[i, 3] / 600;
                   c = ParamsArray[i, 1] / 500;

                   // рисуем в текущем местоположении квадрат 
                   // с заданным цветом
                   Gl.glColor3d(0.2 + a, 0.2 + b, 0.2 + c);
                   
                   Gl.glRectd(ParamsArray[i, 2] - Coef, ParamsArray[i, 3] - Coef, 
                           ParamsArray[i, 2] + Coef, ParamsArray[i, 3] + Coef);
                   
                   
                  //  Thread.Sleep(TimeSpan.FromMilliseconds(100));
                }
              }
              Gl.glFlush();
              AnT.Invalidate();
              // обновляем сожержимое окна 
              

              // обрабатываем возникшие коллизии между квадратим
              
              if (NumberOfAlive > 1)
              {
                // ищем столкнувшиеся квадраты
                // для определения коллизий используем круг вокруг
                // квадрата
                // определяем пересекаются ли две окружности,
                // соответсвующие кадратам i,j

                for (int i = 0; i < MAXSquares - 1; i++)
                   if (ParamsArray[i, 0] == 1.0)
                      for (int j = i + 1; j < MAXSquares; j++)
                        if ((ParamsArray[j, 0] == 1.0)) 
                        {
                           // (x1-x2)(x1-x2)
                           double px = (ParamsArray[i, 2] - ParamsArray[j, 2]) * (ParamsArray[i, 2] - ParamsArray[j, 2]);

                           // (y1-y2)(y1-y2)
                           double py = (ParamsArray[i, 3] - ParamsArray[j, 3]) * (ParamsArray[i, 3] - ParamsArray[j, 3]);

                           // r1 + R1
                           double pr = (ParamsArray[i, 1] + ParamsArray[j, 1]) * (ParamsArray[i, 1] + ParamsArray[j, 1]);

                           // если круги, соответсвующие квадратам, пересекаются,  
                           // расстояние между их центрами меньше суммы радиусов
                           if (px + py < pr)
                           {
                              lock (locker)
                              {
                                // уничтожаем один из квадратов
                                ParamsArray[j, 0] = 0;

                                // увеличиваем радиус большего
                                ParamsArray[i, 1] += ParamsArray[j, 1];

                                NumberOfAlive--;

                              }
                           }
                        }

              } 
           }// lock
           
           // сигнализуруем обработчикам позиции квадратов -  потокам -  об возможности 1 итерации
           // "сигналим" живым потокам
           for (int k = 0; k < NumberOfAlive; k++ )
             wh.Set();

           // wait for 30 miliseconds   
           // Thread.Sleep(TimeSpan.FromMilliseconds(30));    


           //  ждем, пока все не просчитавшие итерацию потоки выполнят ее
           while ( counter < NumberOfAlive )
            Thread.Sleep(TimeSpan.FromMilliseconds(15));

           counter = 0;
        }
        
      }
      //----------------------------------------------------------------------------

      private static void ProcessingSquares(object n)
      {

         int number = (int)n; 

         int IsAlive = 1;

         double radius, Xposition,Yposition,XpositionIncrement,YpositionIncrement;

         string s = number.ToString();

         Thread.CurrentThread.Name = s;

         // lock (locker)
         {
            radius = ParamsArray[number, 1];

            Xposition = ParamsArray[number, 2];

            Yposition = ParamsArray[number, 3];
         }
         
         // задаем вектор перемещения
         XpositionIncrement = Rand.Next(10, 150) / Rand.Next(150, 500);

         YpositionIncrement = Rand.Next(10, 150) / Rand.Next(150, 500);

           do
         {
            // ожидать сигнала о дальнейшем просчете. 
                      
            wh.WaitOne();

            Thread.Sleep(TimeSpan.FromMilliseconds(100));

            // просчитываем следующую позицию
            Xposition += XpositionIncrement;
            Yposition += YpositionIncrement;

            // обрабатываем столкновение с границами области, если нобходимо.

            // левая граница
            if (Xposition < radius)
            {
               Xposition = radius;
               XpositionIncrement = -XpositionIncrement;
            }
            // правая граница. 
            else
               if (Xposition > 800 - radius)
               {
                 Xposition = 800 - radius;
                 XpositionIncrement = -XpositionIncrement;
               }
            // нижняя граница
            if (Yposition < radius)
            {
               Yposition = radius;
               YpositionIncrement = -YpositionIncrement;
            }
            //верхняя граница
            else
               if (Yposition > 600 - radius)
               {
                 Yposition = 600 - radius;
                 YpositionIncrement = -YpositionIncrement;
               }

            // записываем вычисленную позицию 
            lock (locker)
            {
               ParamsArray[number, 2] = Xposition;
               ParamsArray[number, 3] = Yposition;

            }

            // сигнализируем об окончании просчета. 
            // wh1.Set();
            //
            //Interlocked.Increment(ref  counter);

            lock (lockerforsum)
            {
               counter++;
            }

            //  Thread.Sleep(TimeSpan.FromMilliseconds(10));

            // обновляем данные о необходимости еще 1-ой итерации
            lock (locker)
            {
               IsAlive = (int)ParamsArray[number, 0];
            }

         } while ((IsAlive == 1));                        
                    
      }
      
      
      private void Form1_Load(object sender, EventArgs e)
      {        
        // инициализация Glut 
        Glut.glutInit();
        Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE);

        // очитка окна 
        Gl.glClearColor(255, 255, 255, 1);

        Gl.glViewport(0, 0, AnT.Width, AnT.Height);

        //Активация проекционной матрицы
        Gl.glMatrixMode(Gl.GL_PROJECTION);

        //Очистка матрицы
        Gl.glLoadIdentity();

        // настраиваем проекцию
        Glu.gluOrtho2D(0.0, AnT.Width, 0.0, AnT.Height);

        // установка объектно-видовой матрицы 
        Gl.glMatrixMode(Gl.GL_MODELVIEW);

       
        ParamsArray = new double[MAXSquares, 4];


        // заполняем матрицу случайными данными
        for (int i = 0; i < MAXSquares; i++)
        {
           ParamsArray[i, 0] = 1.0;

           ParamsArray[i, 1] = Rand.Next(1, 75);

           ParamsArray[i, 2] = Rand.Next(50, 750);

           ParamsArray[i, 3] = Rand.Next(50, 550);

           // запускаем поток, который каждую итерацию
           // вычисляет  позицию для квадрата, с учетов его направления двивжения
           // передаем потоку его номер i       
           Thread t;

           t = new Thread(ProcessingSquares);

           t.Start(i);

        }


         NumberOfAlive = MAXSquares;


        // количесвто потоков, выполневших 1 итерацию, после обновления кадра
        counter = 0;
            
        
        
        // запускаем основную функции обработки
        timer1.Start();
      }

      private void timer1_Tick(object sender, EventArgs e)
      {
        Admin();
        
      }
   }
}


неужели придется рисовать в консоли...блин, если в пятницу не сдам, зачета не будет. . . =((

0       582        16.12.2010        5
0  
16.12.2010 00:00:00
В общем программа должна работать так: создается и заполняется матрица хранящая данные об каждом квадрате ( жив или нет, радиус, позиция) и создаются потоки для обработки позиции каждого квадрата. Затем вызывается таймер, который раз в 300 мс вызывает функцию Админ, в которой происходит отрисовка текущих квадратов и проверка на столкновение друг с другом. ЗАтем, клгда проверка выполнилась, Админ «сообщает» о возможности еще 1 итерации потокам. ПОтоки после просчета сигнализирую о том что они завершили, и обновляет вычисленные координаты, т.е записывают в матрицу данные. Далее цикл повторяется.
Ссылка 0  
0  
16.12.2010 00:00:00
Здравствуйте

Все доброе утро, скажите, почему при зацикливании какого-либо куска кода, ответственного за отрисовку изображение не выводится на экран? Вот, во всех уроках используется таймер, который в некоторые промежутки времени вызывает функцию отрисовки и это работает. Но, если зациклить эту же функцию и стопить поток, например, Thred.Sleep(TimeSpan.FromMiliceconds(300)), то работать не будет. Почему так происходит?

Я ознакомился только частично/вскользь (просто сейчас очень занят).
У вас

AnT.Invalidate();

Вызывается единожды — попробуйте добавить его во все зацикленные куски кода, например вместо Thred.Sleep(TimeSpan.FromMiliceconds(300)).

Просто мне с первых слов показалось что вся проблема как раз в том, что ваши зацикленные куски кода не обновляют окно.

Если это не поможет — я позже постараюсь глянуть подробнее.
Ссылка 0  
0  
16.12.2010 00:00:00
Проблема и в этом тоже, но она, видимо, следствие того, что форма «залипает» после нескольких итераций. Т.е, подвигать ее можно, но если навести на активную область, то курсор в виде «загрузки». Потом же она совсем виснет и потоки «исчезают», два из них должны оставаться.

Попробовал вообще убрать Tao Framework, т.е вообще пустая форма. Происходит та же история, дело тут не в ОпенДжежеле: что-то с потоками накосячил… буду искать ошибку.
Ссылка 0  
0  
16.12.2010 00:00:00
А если во все циклы вписать AnT.Invalidate(); и, допустим, Refresh формы — не меняется в лучшую сторону?
Родитель Ссылка 0  
0  
17.12.2010 00:00:00
Сейчас проблема с потоками, что-то там все падает, потоки «самоубиваются». Отрисовывать по таймеру вполне подходит.
Ссылка 0  

Блоги Esate.ru

Регистрация

Регистрируясь, вы принимаете правила сайта. Если вы не получили код подтв. регистрации - не забудьте проверить папку спам.
Логин*
Email*
Пароль*
Подтверждение пароля*
 
Логин*
Код*
 

Восстановление пароля

Пожалуйста, заполните поля, после чего вы получите код подтверждения на ваш E-mail. Если код не пришел в течении нескольких минут - проверьте папку спам.
Логин

или Email
 
Логин*
Код подтверждения*
Новый пароль*
Подтверждение пароля*
 

Авторизация

Пожалуйста, авторизуйтесь, для входа на сайт с помощью соц. сети:
  • Используйте вашу учетную запись на Facebook.com для входа на сайт.
  • Используйте вашу учетную запись VKontakte для входа на сайт.
  • Используйте вашу учетную запись Google для входа на сайт.

или с помощью аккаунта на сайте:

Логин
Пароль