c# + TaoFramework вопрос про работу с потоками.
Всем доброе утро, скажите, почему при зацикливании какого-либо куска кода, ответственного за отрисовку изображение не выводится на экран ? Вот, во всех уроках используется таймер, который в некоторые промежутки времени вызывает функцию отрисовки и это работает. Но, если зациклить эту же функцию и стопить поток , например, Thred.Sleep(TimeSpan.FromMiliceconds(300)), то работать не будет. Почему так происходит ? Вопрос возник потому, что почему-то основное окно зависает, если выполняются какие-либо другие потоки, хотя все функции OpenGL вызываются из одного ( главного) потока. В следующем коде так и происходит, и почему-то потоки “самоубиваются” в процессе. Уже 3 дня не могу понять почему. Вообще, задание такое : есть n квадратов , для каждого квадрата свой поток. Квадраты двигаются в некотором направлении. При столкновении один из квадратов-потоков убивается, другой увеличивается в размере.
Изначально написал так, что каждый квадрат это объект, который может просчитывать свою позицию и отрисовывать себя в нужном месте. Не заработало. Как понял, все openGL функции должны использоваться в том потоке, где был определен контекст рендеринга. Переделал отрисовку в основном потоке. Все равно не заработало, причем странно то, что даже овно приложения не создавалось. В общем, привожу ниже последний вариант, он работате пару итераций а потом окно виснет и почему-то потоки убиваются. . . уже не знаю что с этим делать =((( Вообще можно ли Tao использовать в многопточном приложении ? Скорее всего это я где-то ошибся. . .
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();
}
}
}
неужели придется рисовать в консоли…блин, если в пятницу не сдам, зачета не будет. . . =((