v.korleone
Помогающий
Offline
|
|
« Ответ #120 : 05-01-2009 12:56 » |
|
Вад, я был прав... Препод, сказал, что нужно также сделать, чтобы ввод из файла и вывод студентов на экран, осуществлялся с помощью одного потока. Я так думаю, что сделаю еще одну функцию типа этой "unsigned __stdcall CalcAvg (void * arg)", только внутрь запихну две функции: void inputstfile(Student s[],int &m); // Функция ввода из файла void outputst(Student s[],int m); // Функция вывода на экран массива студентов Как думаешь, прокатит? Еще, препод пожелал, чтобы я поставил семафор который будет контролировать, чтобы когда первый поток работает с файлом, остальные 3 ожидали, а также этот семафор дает команду, что можно приступить к вычислениям среднего, когда файл будет загружен, первым потоком. Хочу знать твои пожелания при решении данной задачи.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #121 : 05-01-2009 12:59 » |
|
RXL, здесь абсолютно согласен 2. Не пости несколько сообщений подряд, когда можно отредактировать предыдущее. В следующий раз не буду слеплять их а буду удалять. извиняюсь. Со всем остальным ознакомлюсь.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #122 : 05-01-2009 13:44 » |
|
v.korleone, не совсем уловил суть. Преподаватель хочет, чтобы потоки поочерёдно сами читали из файла студентов? А как, по его мысли, быть с 1-м заданием, про среднее по дисциплине - 4 раза прочитать весь файл, чтобы у каждого потока были все данные? Странно как-то...
А с семафором всё, в принципе, ясно: семафор нужен, чтобы только один поток одномоментно мог читать что-то из файла, а остальные, если им понадобился доступ к файлу, ожидали, пока не читающий не освободит этот файл и не просигнализирует с помощью семафора.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #123 : 05-01-2009 14:00 » |
|
Вад, насколько я понял он хочет чтобы один поток загрузил все в память, а остальные брали данные из памяти, как-то так. Такой вариант возможен?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #124 : 05-01-2009 14:12 » |
|
А, кажется, понимаю. Он имеет в виду конвейерную схему? Т.е. один отдельный поток загружает данные и даёт сигнал остальным потокам, что можно начинать этими данными пользоваться? Что ж, тогда задание логичное.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #125 : 05-01-2009 14:27 » |
|
Точно! Ты правильно понял! С чего начать?
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #126 : 05-01-2009 14:29 » |
|
сделал так: unsigned __stdcall vvod( void * arg) // Функція потоку { int n,N=100; Student a[N]; inputstfile(a,n); in.close(); outputst(a,n); return 0; } но остальные потоки не видят, данных загруженых этим потоком. Средний бал для все студентов "0", поля таблицы, где должны быть студенты пусты.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #127 : 05-01-2009 14:39 » |
|
v.korleone, правильно - откуда бы им знать о твоих локальных переменных и внутренних действиях? Нужно сделать результат доступным - по тому же принципу, что и в уже выполненных задачах. Также придётся предоставлять доступ к семафору нескольким потокам - у тебя ведь он будет один, насколько я понимаю? (правда, с семафором можно и проще - использовать именованный семафор)
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #128 : 06-01-2009 06:46 » |
|
Вад, сделал вот так: Вот структура (та которая для подсчета среднего по дисциплинам) добавил туда еще "n": struct STask // Структура, которая используется для подсчета среднего для каждой дисциплины { Student *src; // Исходные данные int size; // Число элементов в src int subj; // Дисциплина, для которой считаем среднее float avg; // Средний балл - используется для сохранения результата int n; }; Вот код самой функции: unsigned __stdcall InOut (void * arg) { STask *task = (STask*) arg; if (task) // Проверка передачи параметров { inputstfile(task->src,task->n); in.close(); outputst(task->src,task->n); return 0; } else return 1; // Ошибка! } Все компилится без ошибок, выводит студентов на экран, но не считает среднее по дисциплинам, а среднее для студентов считает. Вот реализация вызова в главной программе, потока для вывода на экран: STask tasks[4]; tasks[i].src = a; Thread[0] = (HANDLE)_beginthreadex(NULL, 0, InOut, &tasks[i], 0, &tid); WaitForMultipleObjects(1, Thread, TRUE, INFINITE); CloseHandle(Thread[0]); Что может быть? P.S. Как правильно записать "tasks[i].src = a;" или "tasks[0].src = a;" ? P.S.P.S. Я вот, что подумал может семофор пора добавлять (и причина именно в этом)? Если да, то не мог бы ты расказать, как и куда его ставить.
|
|
« Последнее редактирование: 06-01-2009 09:13 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #129 : 06-01-2009 10:43 » |
|
Да, семафор добавлять, пожалуй, самое время. В целом-то представляешь, что такое семафор, и как им пользоваться?
И ещё: думаю, я бы сделал отдельную структуру для задачи InOut - там и нужно-то только массив прочитать и размер его вернуть, остальные поля в STask избыточны. А ещё, в прежней версии функции main у тебя был жёстко прописан размер в 20 элементов при выводе на экран, а для подсчёта в задачи в первом случае передавалось n, которое вычислялось в процессе чтения файла - оно потерялось, и ничего считаться не будет, потому что n = 0. Вторая же задача не совсем верно работает, поскольку не делит массив на ровные части n/4, а просто берёт по 5 студентов в каждую задачу. А если студентов в файле будет больше или меньше?
|
|
« Последнее редактирование: 06-01-2009 10:47 от Вад »
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #130 : 06-01-2009 17:59 » |
|
Вад, спасибо, за подсказки. Сделал структуру. Теперь вопрос: А ещё, в прежней версии функции main у тебя был жёстко прописан размер в 20 элементов при выводе на экран, а для подсчёта в задачи в первом случае передавалось n, которое вычислялось в процессе чтения файла - оно потерялось, и ничего считаться не будет, потому что n = 0.
Больше мест с переменной n, в функции main, я не заметил: max = a[0].col[3]; for(i = 1; i < n; i++) if (a[i].col[3]>max) max = a[i].col[3]; Ты хочешь сказать чтобы включить эту функцию в unsigned __stdcall InOut (void * arg)?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #131 : 06-01-2009 18:07 » |
|
Какую функцию? Куда внести? Я про это говорил: for (int i = 0; i < 4; ++i) { tasks[i].src = a; // было: tasks[i].src = s; tasks[i].size = n; tasks[i].subj = i; Thread[i] = (HANDLE)_beginthreadex(NULL, 0, CalcAvg, &tasks[i], 0, &tid); }
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #132 : 06-01-2009 18:26 » |
|
Это для подсчета среднего по дисциплинам, ты хочешь сказать нужно сделать аналогично для вывода на экран.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #133 : 06-01-2009 18:45 » |
|
Я хочу сказать, что если у тебя ввод данных будет в отдельном потоке, и потоки, выполняющие CalcAvg не будут знать, сколько там элементов было прочитано в отдельном потоке, то ничего они считать не будут.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #134 : 06-01-2009 18:54 » |
|
Вот добавил "n" при вызове: IOput inouts[4]; inouts[0].src = a; inouts[0].n = n; Thread[0] = (HANDLE)_beginthreadex(NULL, 0, InOut, &inouts[0], 0, &tid); WaitForMultipleObjects(1, Thread, TRUE, INFINITE); CloseHandle(Thread[0]); вот функция для потока: unsigned __stdcall InOut (void * arg) { IOput *inout = (IOput*) arg; if (inout) // Проверка передачи параметров { inputstfile(inout->src,inout->n); in.close(); outputst(inout->src,inout->n); return 0; } else return 1; // Ошибка! } Каким образом им (потокам) можно сообщить сколько там элементов было прочитано в отдельном потоке?
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #135 : 06-01-2009 18:58 » |
|
IOput inouts[4]; inouts[0].src = a; inouts[0].n = n; Thread[0] = (HANDLE)_beginthreadex(NULL, 0, InOut, &inouts[0], 0, &tid); WaitForMultipleObjects(1, Thread, TRUE, INFINITE); CloseHandle(Thread[0]); OMG, а зачем тебе массив из 4х структур? Каким образом им (потокам) можно сообщить сколько там элементов было прочитано в отдельном потоке? А сам как думаешь?
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #136 : 06-01-2009 19:00 » |
|
Невнимательный я, невнимательный!!! Неужели указателями??? Семафором??? Может "n" присвоить 20, но это тоже пожалуй не выход? Не знаю... Вад, ну ответь, пожалуйста. Может сделать, чтобы функциия возращала???
|
|
« Последнее редактирование: 06-01-2009 19:52 от v.korleone »
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #137 : 06-01-2009 20:09 » |
|
Вад, но я честно не знаю, как? Скажи... Может здесь, что то не так (вроде все как ты писал)? Структура правильна:(?) struct IOput // Структура, которая используется для вывода массива n { Student *src; // Исходные данные int n; // };
|
|
« Последнее редактирование: 06-01-2009 20:20 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #138 : 06-01-2009 20:41 » |
|
Чтобы значение было одно для всех потоков, даже если кто-то один это число меняет, нужно, чтобы все владели указателями на одну и ту же область памяти, где хранится число.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #139 : 06-01-2009 20:42 » |
|
так я и пишу вроде *src, или это не то?
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #140 : 06-01-2009 20:50 » |
|
inouts[0].src = a; inouts[0].size = 20; Может как-то так? Может n=20 и все... Но я пробовал буквально так, не получается
|
|
« Последнее редактирование: 06-01-2009 20:56 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #141 : 06-01-2009 21:04 » |
|
Ну, а размер массива?
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #142 : 06-01-2009 21:14 » |
|
... const int N = 100; ... Student a[N]; // Массив студентов Всеравно не вкурю! Ну, а размер массива? - не понял, понял так как написал вверху...
|
|
« Последнее редактирование: 06-01-2009 21:21 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #143 : 06-01-2009 21:23 » |
|
Как к твоему int n в структуре IOput получат доступ остальные потоки, когда им потребуется знать, сколько студентов в списке?
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #144 : 06-01-2009 21:31 » |
|
Сделать в остальных 2 структурах указатель на IOput? Правильно???
|
|
« Последнее редактирование: 06-01-2009 21:35 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #145 : 06-01-2009 21:39 » |
|
Ну, можно и так.
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #146 : 06-01-2009 21:41 » |
|
Вад, разобрался с предыдущей задачей. Перехожу к семофорам. Знаю, немного теории, что семафоры используются для синхронизации, используют счетчик т.д. т.п. (на практических занятиях мы их не расматривали, только на лекциях). Также теоретически знаю создание семафора: HANDLE CreateSemaphore ( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // атрибут доступа LONG lInitialCount, // инициализированное начальное состояние счетчика LONG lMaximumCount, // максимальное количество обращений LPCTSTR lpName // имя объекта ); У меня вопрос по практике, куда его вставлять? И как с ним обращаться? Это "LONG lMaximumCount, // максимальное количество обращений" равно по всей видимости 3 т.к. 3 потока ждут? Или это все же LONG lInitialCount, // инициализированное начальное состояние счетчика? lpName а здесь, что Thread[0]? А "LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // атрибут доступа" чему равно? Новый вопрос: как лучше для данной задачи сделать, семафорами или может быть функцией ожидания?
|
|
« Последнее редактирование: 07-01-2009 10:36 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #147 : 07-01-2009 10:58 » |
|
|
|
|
Записан
|
|
|
|
v.korleone
Помогающий
Offline
|
|
« Ответ #148 : 07-01-2009 11:12 » |
|
Вад, в том то и дело, что я напутал, он сказал осуществить задачу синхронизации, а как это сделать, нужно смотреть самому т.е. как будет лучше. Что скажешь? Есть мысль использовать события, хочу узнать твое мнение.
|
|
« Последнее редактирование: 07-01-2009 11:26 от v.korleone »
|
Записан
|
|
|
|
Вад
|
|
« Ответ #149 : 07-01-2009 11:33 » |
|
В принципе, можно и событие. Почему нет?
|
|
|
Записан
|
|
|
|
|