Консультация № 184731
10.12.2011, 20:28
194.47 руб.
0 5 1
Здравствуйте! У меня возникли сложности с таким вопросом:
Необходимо Разработать программу, которая создает в отдельном потоке случайный массив А из N целых чисел в диапазоне от -999 до 999 выводит на экран эти числа. Создание и вывод элементов массива производится через заданное время T, N и T вводятся пользователем до запуска процесса. Массив обрабатывается двумя другими потоками В и С, работающими параллельно с потоком, создающим массив. Все потоки выводят результаты своей работы в текстовые окна, каждый поток в свое окно.
А)Определение длины пространственной ломаной линии, соединяющей точки, координаты которых заданы каждой тройкой чисел
Б)Вычисление отклонений всех чисел от округленного среднего арифметического

Можете назначить свою цену если в этом есть необходимость.

Обсуждение

давно
Мастер-Эксперт
425
4118
11.12.2011, 13:02
общий
11.12.2011, 13:05
Массив обрабатывается двумя другими потоками В и С, работающими параллельно с потоком, создающим массив.

Вот это вот, непонятно, каким боком относится к основной части задания. В чём заключается смысл обработки. Поясните.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
12.12.2011, 09:33
общий
Здравствуйте.
Просто цель данной задачи является создание много поточного приложения.
В принципе можно не включать данную обработку в задание.

Заранее спасибо...


Неизвестный
15.12.2011, 03:26
общий
Примерно так надо, наверно. Правда, тут вывод в консоль, не в разные окна, но суть одна.
[code h=300]#include <Windows.h>
#include <iostream>
#include <math.h>
#include <time.h>
#include <string>
#include <sstream>
using namespace std;

int* A;
int N, T;
HANDLE g_BusyEvent[2];

int Random (int min, int max)
{
return rand()%(max-min) + min ;
}

double Length (int x1, int y1, int z1, int x2, int y2, int z2)
{
double val = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
return sqrt (val);
}

DWORD WINAPI CreateArrayThread(void *pParam) //Рабочий поток
{
//WaitForSingleObject (g_BusyEvent[0], INFINITE);
WaitForMultipleObjects (2, g_BusyEvent, TRUE, INFINITE);
ResetEvent (g_BusyEvent[1]);
cout << "\nNew array: ";
srand (time(NULL));
for (int i=0; i<N; i++) {
A[i] = Random (-999, 999);
cout << A[i] << ' ';
}
SetEvent(g_BusyEvent[1]);
SetEvent(g_BusyEvent[0]);
return 0;
}

DWORD WINAPI LengthThread(void *pParam) //Рабочий поток
{
WaitForSingleObject (g_BusyEvent[1], INFINITE);
ResetEvent (g_BusyEvent[0]);
cout << "\nLength of line: ";
double s = 0;
for (int i=0; i<N-6;) {
s+=Length(A[i++], A[i++], A[i++], A[i++], A[i++], A[i++]);
}
cout << s;
SetEvent(g_BusyEvent[1]);
SetEvent(g_BusyEvent[0]);
return 0;
}

DWORD WINAPI AverageThread(void *pParam) //Рабочий поток
{
WaitForSingleObject (g_BusyEvent[1], INFINITE);
ResetEvent (g_BusyEvent[0]);
cout << "\nDisplacement: ";
int s = 0;
for (int i=0; i<N; i++)
s+=A[i];
s/=N;
for (int i=0; i<N; i++)
cout << s-A[i] << ' ';
SetEvent(g_BusyEvent[1]);
SetEvent(g_BusyEvent[0]);
return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
cout << "Enter count: ";
cin >> N;
cout << "Enter time (seconds): ";
cin >> T;
A = new int [N];
g_BusyEvent[0] = CreateEvent(NULL, FALSE, TRUE, NULL); //Создаём событие
g_BusyEvent[1] = CreateEvent(NULL, FALSE, TRUE, NULL); //Создаём событие
DWORD dwID;
while (true) {
CloseHandle (CreateThread(NULL, 0, CreateArrayThread, NULL, 0, &dwID)); //Создаём поток
CloseHandle (CreateThread(NULL, 0, LengthThread, NULL, 0, &dwID)); //Создаём поток
CloseHandle (CreateThread(NULL, 0, AverageThread, NULL, 0, &dwID)); //Создаём поток
Sleep (T*1000);
//system("pause");
}
return 0;
}
[/code]
Неизвестный
16.12.2011, 13:47
общий
это ответ
Здравствуйте, MishaSurgut!
Вот пример такой программы. Правда, тут всё выводится в одну

консоль, чтобы выводить в разные окна надо делать оконное приложение и в каждом потоке

вместо cout выводить на какой-нибудь свой контрол.
В программе создаётся по три потока на

каждой итерации, каждый выполняет свою задачу. Один заполняет массив, другой считает длину

линии, третий ищет отклонения. Для синхронизации потоков используются события (event) -

одно для потока создания и одно для потоков обработки.
Используемые WinAPI функции:


CreateEvent

Эта функция создаёт или открывает существующее событие, возвращаемым

значением является его описатель.
Код:
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES

lpEventAttributes, //Аттрибуты защиты
BOOL bManualReset, //Ручной сброс
BOOL

bInitialState, //Состояние при создании
LPCTSTR lpName //Имя (если необходимо)
);

Параметры функции:
lpEventAttributes - в качестве этого параметра передаётся адрес

структуры вида:
Код:
 typedef struct _SECURITY_ATTRIBUTES {
DWORD nLength; //Размер

структуры (как правило, берётся sizeof)
LPVOID lpSecurityDescriptor; //Указатель на

дескриптор, контролирующий совместное

//использование объекта
BOOL bInheritHandle; //Флаг, разрешающий наследование объекта

дочерним процессом
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES;

bManualReset - если

этот параметр true, то помещение объекта в несигнальное состояние нужно производить вручную

(путём вызова спецмальной функции). Если же передать сюда false, то событие будет обладать

автосбросом, т.е. автоматически возвращаться в несигнальное состояние.
bInitialState - если

этот параметр равен true, начальное состояние события - сигнальное, в противном случае -

несигнальное.
Более подробную информацию можно получить в

MSDN.


WaitForSingleObject

Эта функция приостанавливает выполнение текущего потока до тех пор,

пока указанный в её параметрах объект ядра не придёт в сигнальное состояние (также возможен

выход по таймауту). Применяется для ограниничения доступа к разделяемым ресурсам.

Параметром чаще всего служит событие, семафор или мьютекс, но также в качестве параметра

может выступать уведомление (notification), процесс, поток и некоторые другие объекты.

Возвращаемое значение показывает, что послужило выходом из функции. Это может быть

WAIT_ABANDONED (специфическое значение, возвращаемое в случае завершения потока, владеющего

мьютексом), WAIT_OBJECT_0 (объект получил сигнальное состояние - в этом случае функция сама

переводит его в несигнальное, а для семафора наращивает счётчик числа занятых ресурсов),

WAIT_TIMEOUT (функция вышла по таймауту).
Код:
DWORD WaitForSingleObject(
HANDLE

hHandle, //Описатель объекта ядра, сигнальное состояние которого нас интересует
DWORD

dwMilliseconds //Таймаут, по истечению которого прервать ожидание
);
Рассмотрим

подробнее некоторые параметры функции:
dwMilliseconds - здесь можно указать любой

необходимый таймаут, кроме того, если указать 0, функция вернёт потоку управление сразу

(таким образом можно проверить состояние объекта), а если указать константу INFINITE,

функция не будет учитывать время и будет ждать только сигнального состояния объекта ядра.
Более подробную информацию можно получить в MSDN.
CreateThread
Эта функция создаёт поток

внутри адресного пространства текущего процесса. Возвращает описатель созданного потока.

Функция полезна, когда, например, нужно выполнять какие-то действия в оконном приложении,

но не отключать при этом его интерфейс. В общем случае поток начинает работу сразу после

вызова этой функции, и все действия, которые он выполняет, не мешают работе программы.
Код:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, //Аттрибуты защиты


SIZE_T dwStackSize, //Размер стека потока (если указать 0, то берётся по умолчанию)


LPTHREAD_START_ROUTINE lpStartAddress, //Адрес стартовой функции
LPVOID lpParameter,

//Параметр для передачи потоку
DWORD dwCreationFlags, //Служебные флаги
LPDWORD

lpThreadId //ID потока
);

Рассмотрим подробнее некоторые параметры функции:
lpStartAddress - указатель на стартовую функцию потока (т.е. её название), которую надо

объявить внутри приложения. Она должна иметь определённый вид:
Код:
DWORD WINAPI 

ThreadProc( //Имя функции может быть произвольным
LPVOID lpParameter
);

lpParameter - параметр, передаваемый в стартовую функцию потока. Если потоку необходимо

передать несколько параметров, следует либо использовать глобальные переменные, либо

объявлять структуру со всеми необходимыми данными и передавать её.
dwCreationFlags - в

основном этот параметр используется для того, чтобы обозначить, следует ли запустить поток

сразу после создания или по вызову функции ResumeThread (в первом случае в параметре можно

передать 0, во втором - флаг CREATE_SUSPENDED).
lpThreadId - возвращаемый параметр - id

потока, который иногда может быть полезен (например, если потоку будет посылаться

сообщение). Если id не нужен, можно передать NULL.
Более подробную информацию можно получить

в MSDN.
CloseHandle

, собственно, делает именно то, как называется: закрывает используемый дескриптор.
Код в

приложении, проверено на MS VS 2010.
Будут вопросы, обращайтесь.
Удачи!

Приложение:
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <time.h>
#include <string>
using namespace std;

int* A; //глобальный массив
int N, T; //число элементов, время
HANDLE g_BusyEvent[2]; //события

int Random (int min, int max) //рандом от min до max
{
return rand()%(max-min) + min ;
}

double Length (int x1, int y1, int z1, int x2, int y2, int z2) //вычисление длины линии между пространственными точками
{
double val = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1);
return sqrt (val);
}

DWORD WINAPI CreateArrayThread(void *pParam) //Поток формирования массива
{
WaitForSingleObject (g_BusyEvent[0], INFINITE); //ждём допуска
ResetEvent (g_BusyEvent[1]); //запрещаем обработки
cout << "\nNew array: ";
srand (time(NULL));
for (int i=0; i<N; i++) {
A[i] = Random (-999, 999); //заполняем массив
cout << A[i] << ' ';
}
SetEvent(g_BusyEvent[0]);
SetEvent(g_BusyEvent[1]);
return 0;
}

DWORD WINAPI LengthThread(void *pParam) //Рабочий поток
{
WaitForSingleObject (g_BusyEvent[1], INFINITE); //ждём разрешение на обработку
SetEvent(g_BusyEvent[1]); //разрешаем параллельную обработку
ResetEvent (g_BusyEvent[0]); //запрещаем переформирование массива
cout << "\nLength of line: ";
double s = 0;
for (int i=0; i<N-6;) { //считаем длину
s+=Length(A[i++], A[i++], A[i++], A[i++], A[i++], A[i++]);
}
cout << s;
SetEvent(g_BusyEvent[0]); //разрешаем переформирование
return 0;
}

DWORD WINAPI AverageThread(void *pParam) //Рабочий поток
{ //аналогично предыдущему
WaitForSingleObject (g_BusyEvent[1], INFINITE);
SetEvent(g_BusyEvent[1]);
ResetEvent (g_BusyEvent[0]);
cout << "\nDisplacement: ";
int s = 0;
for (int i=0; i<N; i++)
s+=A[i];
s/=N;
for (int i=0; i<N; i++)
cout << s-A[i] << ' ';
SetEvent(g_BusyEvent[0]);
return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
cout << "Enter count: ";
cin >> N;
cout << "Enter time (seconds): ";
cin >> T;
A = new int [N];
g_BusyEvent[0] = CreateEvent(NULL, FALSE, FALSE, NULL); //Создаём событие
g_BusyEvent[1] = CreateEvent(NULL, FALSE, TRUE, NULL); //Создаём событие
DWORD dwID;
while (true) {
SetEvent (g_BusyEvent [0]); //разрешаем формирование
ResetEvent (g_BusyEvent[1]); //запрещаем обработки
CloseHandle (CreateThread(NULL, 0, CreateArrayThread, NULL, 0, &dwID)); //Создаём поток
CloseHandle (CreateThread(NULL, 0, LengthThread, NULL, 0, &dwID)); //Создаём поток
CloseHandle (CreateThread(NULL, 0, AverageThread, NULL, 0, &dwID)); //Создаём поток
Sleep (T*1000); //выжидаем заданное время
//system("pause"); //если хотите успеть смотреть результат на каждой итерации
}
return 0;
}
Неизвестный
18.12.2011, 19:09
общий
Добрый день... забыл снять эту задачу, я уже решил эту задачку правда в Delphi.... Но все равно огромное спасибо...
Форма ответа