Консультация № 175586
24.12.2009, 15:40
35.00 руб.
0 2 0
Здравствуйте,уважаемые эксперты!Помогите ,пожалуйста,со следующей задачей:
Есть решение задачи(само решение и условие в приложении) ,но необходимо сделать так,чтобы отдельный поток управлял отдельной молекулой(их кол-во м.б. малым 5 или10) и осуществить синхронизацию потоков,а не как в решении всё моделирование происходит в одном потоке.

Приложение:
ЗАДАНИЕ:
Написать задачу,отображающую поведение молекул идеального газа в закрытом сосуде:
А)Создаётся N потоков,каждый из которых занимается отрисовкой в заданном Canvas движущихся кругов(молекул).
Б)Круги должны взаимодействовать со стенками сосуда(границами Canvas) и с друг другом.
В)Взаимодействие между потоками-отрисовщиками должно быть реализовано потоком-администратором,который постоянно через заданное малое время опрашивает потоки-отрисовщики об их текущем положении и в соответствии с ним раздаёт кванты перемещения.


#include "Vessel.h"

using namespace System::Drawing;

int CompareX(Molecule ^a, Molecule ^b)
{
return a->Point.X.CompareTo(b->Point.X);
}

RectangleF MovingRectangle(Molecule ^M)
{
float x1, x2, y1, y2;
x1=M->Point.X;
x2=M->_newpoint.X;
y1=M->Point.Y;
y2=M->_newpoint.Y;
if(x1 > x2) {float t=x1; x1=x2; x2=t; }
if(y1 > y2) {float t=y1; y1=y2; y2=t; }
return RectangleF(x1, y1, x2-x1, y2-y1);
}

void Vessel::Tik()
{
for each(Molecule ^M in Molecules)
{
M->_newvelocity=M->Velocity;
float c=M->Point.X+M->Velocity.X;
if(c<0)
{
c=-c;
M->_newvelocity.X=-M->Velocity.X;
}
else if(c>Width)
{
c -= 2 * (c - Width);
M->_newvelocity.X=-M->Velocity.X;
}
M->_newpoint.X=c;

c=M->Point.Y+M->Velocity.Y;
if(c<0)
{
c=-c;
M->_newvelocity.Y=-M->Velocity.Y;
}
else if(c>Height)
{
c-= 2 * (c - Height);
M->_newvelocity.Y=-M->Velocity.Y;
}
M->_newpoint.Y=c;
}
}

void Vessel::FindCollisions()
{
Molecules->Sort(gcnew System::Comparison<Molecule^>(CompareX));
int cnt=Molecules->Count;
for(int i=1; i<cnt; i++)
{
Molecule ^M1=Molecules[i];
RectangleF R1=MovingRectangle(M1);
int k;
Molecule ^M2;
for(k=i-1, M2=Molecules[i-1]; k>=0 && (M1->Point.X - M2->Point.X <= 1.0); k--)
{
M2=Molecules[k];
RectangleF R2=MovingRectangle(M2);
if(R1.IntersectsWith(R2))
CollisionFound(M1, M2);//обрабатываем столкновение между молек-ми
}
}
}

void Vessel::CollisionFound(Molecule ^M1, Molecule ^M2)
{
M1->Collided=5;
M2->Collided=5;
}

void Vessel::Tak()
{
for each(Molecule ^M in Molecules)
{
M->Point=M->_newpoint;
M->Velocity=M->_newvelocity;
}
}

void Vessel::StartSimulation()
{
Simulating=true;
while(Simulating)
{
Tik();
FindCollisions();
Tak();
System::Threading::Thread::Sleep(20);
}
}

////класс "сосуд"
#pragma once
#include "Molecule.h"
using namespace System::Collections::Generic;

ref class Vessel
{
public:
Vessel(float width, float height):Width(width),Height(height){Molecules = gcnew List<Molecule^>();}

List<Molecule^> ^Molecules;
float Width, Height;
bool Simulating;

void StartSimulation();

private:
void Tik();
void Tak();
void FindCollisions();
void CollisionFound(Molecule ^M1, Molecule ^M2);//В этом методе надо обрабатывать столкновения
};
//струк-ра молекула
#pragma once

value struct XY
{
float X, Y;
};

ref struct Molecule
{
public:
XY Point;
XY Velocity;
XY _newpoint;
XY _newvelocity;
int Collided;
};
///определение для формы
#pragma once
#include "Vessel.h"

namespace CWindows {

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::Drawing::Drawing2D;
using namespace System::Threading;

/// <summary>
/// Summary for Form1
///
/// WARNING: If you change the name of this class, you will need to change the
/// 'Resource File Name' property for the managed resource compiler tool
/// associated with all .resx files this class depends on. Otherwise,
/// the designers will not be able to interact properly with localized
/// resources associated with this form.
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Form1(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
float W = ClientSize.Width;
float H = ClientSize.Height;
V=gcnew Vessel(W, H);
Random ^RND= gcnew Random();
for(int i=0; i<200; i++)
{
Molecule ^M = gcnew Molecule();
M->Point.X = RND->NextDouble()*W;
M->Point.Y = RND->NextDouble()*H;

M->Velocity.X = 2 * RND->NextDouble() - 1.0;
M->Velocity.Y = 2 * RND->NextDouble() - 1.0;

V->Molecules->Add(M);
}
Worker = gcnew Thread(gcnew ThreadStart(V, &Vessel::StartSimulation));
Worker->Start();
timer1->Start();
}

protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~Form1()
{
if (components)
{
delete components;
}
}
private: System::ComponentModel::IContainer^ components;
protected:

private:
Vessel ^V;
System::Windows::Forms::Timer^ timer1;
Thread ^Worker;

private: System::Void Form1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)
{
Graphics ^G = e->Graphics;
G->Clear(this->BackColor);
G->CompositingQuality = CompositingQuality::HighQuality;
G->InterpolationMode = InterpolationMode::Bilinear;

for each(Molecule ^M in V->Molecules)
{
Brush ^B;
if(M->Collided > 0)
{
B=Brushes::Red;
M->Collided--;
}
else
B = Brushes::Blue;
G->FillEllipse(B, (int)M->Point.X-2, (int)M->Point.Y-2, 5, 5);
}
}

private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
this->Refresh();
}

private: System::Void Form1_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e)
{
timer1->Stop();
V->Simulating=false;
Worker->Join();
}

#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->components = (gcnew System::ComponentModel::Container());
this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
this->SuspendLayout();
//
// timer1
//
this->timer1->Interval = 40;
this->timer1->Tick += gcnew System::EventHandler(this, &Form1::timer1_Tick);
//
// Form1
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->ClientSize = System::Drawing::Size(694, 347);
this->DoubleBuffered = true;
this->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedSingle;
this->Name = L"Form1";
this->Text = L"Form1";
this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &Form1::Form1_Paint);
this->FormClosing += gcnew System::Windows::Forms::FormClosingEventHandler(this, &Form1::Form1_FormClosing);
this->ResumeLayout(false);

}
#pragma endregion
};
}

Обсуждение

Неизвестный
24.12.2009, 18:17
общий
РАИ:
Вашему преподавателю стоило бы почитать учебник по параллельному программированию. Он заставляет решать в потоках задачу, которая именно для них и не подходит. Здесь ведь все данные крепко связаны. На днях попробую переделать. Хотя, судя по коду из предыдущих вопросов, Вы и сами в состоянии. Тут проблема только в синхронизации по барьеру. Не помню, реализованна ли она в .Net. Если что, самому писать придется.

Но в итоге модель будет сильно отличаться от реальной. Даже в прошлом варианте надо было повозиться, чтобы столкновения отрабатывались как на самом деле, а тут это вообще нереально много кода нужно. Правда, по анимации это, скорее всего, не очень заметно будет.
Неизвестный
24.12.2009, 21:12
общий
Evgenijm!У меня самой не получается,я уже задавала по этому поводу вопрос.На Вас надеюсь(самый простой вариант:) ).
Форма ответа