Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > многопоточное вычисление


Автор: denisminb 13.5.2013, 18:55
Добрый день,подскажите пожалуйста в вопросе многопоточности, читаю книги, смотрю разные реализации, в общем начал практиковаться,не совсем получается мне кажется.
Для примера,может конечно не совсем удачно, взял вычисление числа PI c определенной точностью.
без использования потоков, было нечто такое:
описан прототип фукнции
сама функция
в мейне вызов функции, вывод результата итд
использую 
Код

#include <pthread.h>

для того чтобы работало с потоками добавил в функцию void*
Код

void *pi_calc(void*);

Код

int main()
{
    int id, result;
    pthread_t    our_thread_id;
    id = 1;
    ..........
              ...........
    if (Variant == 2) //Если вычисляем по заданной точности

     result = pthread_create(&our_thread_id,NULL,&pi_calc,&id);
     if (result != 0) {
                perror("Creating the first thread");
              return EXIT_FAILURE;
               }
           pthread_join(our_thread_id, NULL);
           pause();

          /*Код для варианта без использования потоков,вывода результата работы функции
            double* q; // Создали указатель для приема результата
            q=(double*)pi_calc(); // Приняли результат, преобразовав нужным образом тип возвращаемого указателя
           cout<<"Результат : "<<setprecision(20)<< *q << endl;
           free(q);
         */
     return EXIT_SUCCESS;
}


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

Автор: Фантом 13.5.2013, 19:08
Пока что в этом коде результат вычисления функции отображать просто нечему (то, что закомментировано, не в счет).

Автор: denisminb 13.5.2013, 19:14
Цитата(Фантом @ 13.5.2013,  19:08)
Пока что в этом коде результат вычисления функции отображать просто нечему (то, что закомментировано, не в счет).

Код

void *pi_calc(void*arg)
{
    int loc_id = * (int *) arg;
    clock_t startclock = clock();
    double Esp; //Точность вычисления (вариант 2)
    unsigned long delit = 1; //Делитель члена ряда
    cout << "Введите заданную точность вычисления (0.00000001) : ";
    cin >> Esp; //Введем точность
    double* PI;
    PI=(double*)malloc(sizeof(double));
    int i=0;
    double Ryad = 4; //Текуйщи член ряд
    while (Ryad > Esp) //Пока текущий член ряда > нашей заданной точности
    {
                Ryad = (double)4/delit; //Вычислим член ряда
                if (i %2 == 0)
                    *PI+= Ryad;
                else
                 *PI-= Ryad;
                delit+=2;
                i++;
    }

    printf ("Результат: %9.3f",PI);
    return PI;
}


сама функция

Автор: Фантом 13.5.2013, 20:22
Она у Вас просто зацикливается, причем потоки тут совершенно не при чем.

P.S. Кстати, Вы действительно хотите делать ввод параметров в каждом потоке?

Автор: denisminb 13.5.2013, 20:54
Цитата(Фантом @ 13.5.2013,  20:22)
Она у Вас просто зацикливается, причем потоки тут совершенно не при чем.

P.S. Кстати, Вы действительно хотите делать ввод параметров в каждом потоке?

while (Ryad > Esp) - ну да, здесь зацикливание,


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

Автор: Фантом 13.5.2013, 21:00
Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

while (Ryad > Esp) - ну да, здесь зацикливание,

Именно.

Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

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

Конечно. Это и со смысловой, и с технической точки зрения разумнее.

Автор: denisminb 13.5.2013, 22:07
Цитата(Фантом @ 13.5.2013,  21:00)
Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

while (Ryad > Esp) - ну да, здесь зацикливание,

Именно.

Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

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

Конечно. Это и со смысловой, и с технической точки зрения разумнее.

самое интересное,то что функция возвращала правильное значение Pi, без использования потоков

Автор: denisminb 14.5.2013, 21:41
Цитата(Фантом @ 13.5.2013,  21:00)
Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

while (Ryad > Esp) - ну да, здесь зацикливание,

Именно.

Цитата(denisminb @  13.5.2013,  21:54 Найти цитируемый пост)

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

Конечно. Это и со смысловой, и с технической точки зрения разумнее.

можно ещё вопрос?
как думаете лучше вообще переписать алгоритм без использования While?
или например от того чтобы не зацикливало,добавил
Код

                            double Ryad = 1; //Текуйщи член ряд
        while (fabs(Ryad) > Esp && i<100000) //Пока текущий член ряда > нашей заданной точности и кол-во членов ряда <100000
        {
                    Ryad = (double)4/delit; //Вычислим член ряда
                    delit+=2;
                    if (i %2 == 0)
                        PI+= Ryad;
                    else
                        PI-= Ryad;

                    i++;
        }

        cout<<"Результат : "<<setprecision(20)<< PI<< endl;


Автор: Фантом 14.5.2013, 23:53
Цитата(denisminb @  14.5.2013,  22:41 Найти цитируемый пост)

как думаете лучше вообще переписать алгоритм без использования While?

Хм... в каком смысле "лучше"?

Автор: rsm 15.5.2013, 02:57
Цитата(denisminb @  13.5.2013,  20:55 Найти цитируемый пост)
Для примера,может конечно не совсем удачно, взял вычисление числа PI c определенной точностью

Для сугубо численных вычислений лучше использовать http://habrahabr.ru/post/147796/.

Цитата(denisminb @  14.5.2013,  23:41 Найти цитируемый пост)
как думаете лучше вообще переписать алгоритм без использования While?

Цикл нужен так или иначе, просто каждому потоку нужно выделить определённый интервал вычислений количества знаков после запятой, как-то так:
[0, 10000) - первый поток;
[10000, 20000) - второй;
[20000, 30000) - третий;
[20000, 40000) - четвёртый;
и т.д. в том же духе. Оптимальное количество потоков обычно принимают равным количеству ядер процессора * 2 + 1.

Автор: denisminb 15.5.2013, 18:22
Цитата(Фантом @ 14.5.2013,  23:53)
Цитата(denisminb @  14.5.2013,  22:41 Найти цитируемый пост)

как думаете лучше вообще переписать алгоритм без использования While?

Хм... в каком смысле "лучше"?

я просто имел ввиду,как лучше сделать?

Автор: denisminb 15.5.2013, 18:40
Цитата(rsm @ 15.5.2013,  02:57)
Цитата(denisminb @  13.5.2013,  20:55 Найти цитируемый пост)
Для примера,может конечно не совсем удачно, взял вычисление числа PI c определенной точностью

Для сугубо численных вычислений лучше использовать http://habrahabr.ru/post/147796/.

Цитата(denisminb @  14.5.2013,  23:41 Найти цитируемый пост)
как думаете лучше вообще переписать алгоритм без использования While?

Цикл нужен так или иначе, просто каждому потоку нужно выделить определённый интервал вычислений количества знаков после запятой, как-то так:
[0, 10000) - первый поток;
[10000, 20000) - второй;
[20000, 30000) - третий;
[20000, 40000) - четвёртый;
и т.д. в том же духе. Оптимальное количество потоков обычно принимают равным количеству ядер процессора * 2 + 1.

в принципе в теории я понимаю что для того чтобы программа была многопоточная,вычисляла параллельно,нужно распараллелить алгоритм,разбить на блоки.
только не пойму как в моём варианте сделать?
На данном этапе, в цикле вычисляю очередной член ряда и затем суммирую,выхожу из цикла по количеству итераций.
Вы пишите, что нужно разбить на интервалы,этот контекст не совсем понимаю.
я думал если разбить по количеству итераций, но как собрать результаты потоков?тогда нужно для каждого интервала писать свою функцию вызова для pthread_create?


P.S. Нужно сделать без OpenMP, точнее даже нужно два варианта без него и с ним. Но пока его не нужно.
 

Автор: rsm 15.5.2013, 20:01
Цитата(denisminb @  15.5.2013,  20:40 Найти цитируемый пост)
только не пойму как в моём варианте сделать?

Приведённую выше http://habrahabr.ru/post/147796/ всё-таки стоит почитать smile

Автор: denisminb 15.5.2013, 20:26
Цитата(rsm @ 15.5.2013,  20:01)
Цитата(denisminb @  15.5.2013,  20:40 Найти цитируемый пост)
только не пойму как в моём варианте сделать?

Приведённую выше http://habrahabr.ru/post/147796/ всё-таки стоит почитать smile

спасибо за статью,ознакомлюсь, сделал так, с блокировками
Код

#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <sys/neutrino.h>
#include <pthread.h>
#include <errno.h>
#include <sched.h>
#include <unistd.h>
#include <math.h>

#define INTERVALS 100000
#define THREADS 4


using namespace std;

float global_sum = 0.0;
pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;

void *pi_calc(void *);

int main ()
{
  pthread_t tid[THREADS];
  int i,result;
  int t_num[THREADS];

  for (i = 0; i < THREADS; i++)
  {
    t_num[i] = i;
    result = pthread_create(&tid[i], NULL, pi_calc, &t_num[i]);
    if (result != 0) {
     perror("Creating the thread");
     return EXIT_FAILURE;
    }
  }

  for (i = 0; i < THREADS; i++){
      result = pthread_join (tid[i], NULL);
      if (result != 0) {
                perror("Joining the first thread");
                return EXIT_FAILURE;
              }
  }
  cout<<"Результат : "<<setprecision(20)<< global_sum<< endl;
}

void *pi_calc(void *)
{
  double my_pi = 0.0;
  double h = 1.0 / INTERVALS;
  double x;
  int i;
  for (i = 1; i < INTERVALS; i++)
  {
    x = ((double)i - 0.5)*h;
    my_pi = my_pi+ 4.0 / (1.0 + x * x);
  }

  pthread_mutex_lock(&global_lock);
  global_sum = my_pi*h;
  pthread_mutex_unlock(&global_lock);
}



Добавлено через 6 минут и 21 секунду
ага,только не совсем понимаю,как запустить в qnx версию с openMP, как хидер подключить?

Автор: Фантом 16.5.2013, 00:02
Цитата(denisminb @  15.5.2013,  19:22 Найти цитируемый пост)

я просто имел ввиду,как лучше сделать? 

Задача слишком "ненастоящая", чтобы можно было просто так выбирать что-то лучшее. Например, с математической точки зрения лучше воспользоваться оценкой остатка для ряда и, зная необходимую точность, заранее вычислить необходимое число членов (и тогда цикл while, понятно, не нужен).

Автор: denisminb 17.5.2013, 17:13
Цитата(Фантом @ 16.5.2013,  00:02)
Цитата(denisminb @  15.5.2013,  19:22 Найти цитируемый пост)

я просто имел ввиду,как лучше сделать? 

Задача слишком "ненастоящая", чтобы можно было просто так выбирать что-то лучшее. Например, с математической точки зрения лучше воспользоваться оценкой остатка для ряда и, зная необходимую точность, заранее вычислить необходимое число членов (и тогда цикл while, понятно, не нужен).

спасибо, можете прокоментировать код "на сколько он плох или нет" пост - 15.5.2013, 20:26

Автор: Фантом 17.5.2013, 17:51
Цитата(denisminb @  17.5.2013,  18:13 Найти цитируемый пост)

спасибо, можете прокоментировать код "на сколько он плох или нет" пост - 15.5.2013, 20:26 

Это Вам действительно нужно? 

Ну что ж... код плох. Во-первых, по причине странной смеси "французского с нижегородским" - от старого C до чуть более современного C++. Во-вторых, по причине использования Pthreads для задачи в той предметной области, где обычно используются другие инструменты (уже упомянутый выше OpenMP).

Автор: denisminb 18.5.2013, 10:30
Цитата(Фантом @ 17.5.2013,  17:51)
Цитата(denisminb @  17.5.2013,  18:13 Найти цитируемый пост)

спасибо, можете прокоментировать код "на сколько он плох или нет" пост - 15.5.2013, 20:26 

Это Вам действительно нужно? 

Ну что ж... код плох. Во-первых, по причине странной смеси "французского с нижегородским" - от старого C до чуть более современного C++. Во-вторых, по причине использования Pthreads для задачи в той предметной области, где обычно используются другие инструменты (уже упомянутый выше OpenMP).

в стандартном qnx я не могу использовать openMP,поэтому использую pthread

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)