Pthread-Aufgabe

Turps

New Member
#1
Liebe Community,

wir müssen als Hausaufgabe (ja, ich bin so ehrlich) folgenden Code ergänzen:

C++:
#include <stdio.h>

#include <pthread.h>

int max(int a, int b)
{
  return (a>b) ? a : b;
}

int sum(int a, int b)
{
  return a+b;
}

int reduce(int (*op)(int, int),
           int *data,
           int len)
{
  int i;
  int result = data[0];
  for (i = 1; i < len; ++i)
    result = op(result, data[i]);
  return result;
}

int parallel_reduce(int (*op)(int, int),
                    int *data,
                    int len)
{
}

int main() {
  int data[] = {1,2,3,4,5,6,7,8,9,10};

  int m  = reduce(max, data, 10);
  int s = reduce(sum, data, 10);

  printf("max : %i; sum: %i\n", m, s);

  int pm = parallel_reduce(max, data, 10);
  int ps = parallel_reduce(sum, data, 10);

  printf("parallel max : %i; parallel sum: %i\n", pm, ps);
  return 0;
}
Es geht darum, die bereits existierende Funktion reduce mit Hilfe von pthread zu parallelisieren (also parallel_reduce zu implementieren). Da ich leider blutiger C++-Anfänger bin, wäre es gut, wenn ich Hilfe bekomme.

Meine Grundidee:

Man nehme an man hat 4 Threads zu Verfügung. Ich möchte also 4 Threads erstellen, die jeweils die Summe/Maximum eines Teilarrays des Arrays data berechnen. Anschließend soll dann einer von den frei gewordenen Threads die vier Teilergebnisse zu einem Endergebnis berechnen. Der folgende Versuch soll nur andeuten, was ich versuchen möchte.

CSS:
#include <stdio.h>

#include <pthread.h>

// Maximale Threadanzahl
#define MAX_THREAD 4

int max(int a, int b)
{
  return (a>b) ? a : b;
}

int sum(int a, int b)
{
  return a+b;
}

int reduce(int (*op)(int, int),
           int *data,
           int len)
{
  int i;
  int result = data[0];
  for (i = 1; i < len; ++i)
    result = op(result, data[i]);
  return result;
}

int parallel_reduce(int (*op)(int, int),
                    int *data,
                    int len)
{
  pthread_t threads[MAX_THREAD];


  // 4 Threads erstellen
    for (int i = 0; i < MAX_THREAD; i++)
        pthread_create(&threads[i], NULL, (void *(*)(void *))reduce, data((i*len)/4, ((i+1)*len)/4)-((i*len)/4)));


// joining 4 threads i.e. waiting for all 4 threads to complete
    for (int i = 0; i < MAX_THREAD; i++)
        pthread_join(threads[i], NULL);

}

int main() {
  int data[] = {1,2,3,4,5,6,7,8,9,10};

  int m  = reduce(max, data, 10);
  int s = reduce(sum, data, 10);

  printf("max : %i; sum: %i\n", m, s);

  int pm = parallel_reduce(max, data, 10);
  int ps = parallel_reduce(sum, data, 10);

  printf("parallel max : %i; parallel sum: %i\n", pm, ps);
  return 0;
}
Das Grundproblem, soweit ich das verstanden habe ist, dass pthread_create eine Funktion vom Typ void* func (void*) braucht, was bisher ja nicht gegeben ist. Umschreiben sollen wir die (normale) reduce-Funktion aber auch nicht. Zudem müssen an pthread_create auch mehrere Argumente übergeben werden, es wird aber nur einer unterstützt. Deswegen habe ich als Hilfe bekommen, ein struct zu implementieren mit den notwendigen Attributen, um diesen dann an pthread_create zu übergeben. In dem struct muss ja selber wieder auf eine Funktion verwiesen werden (max oder sum) und das Array data muss ja auch abhängig von Thread in Teilabschnitte untergliedert werden (data((i*len)/4, ((i+1)*len)/4)-((i*len)/4)))).

Ich habe schon stundenlang gegooglet, aber nichts gefunden, was mit weiterhilft.

Ich hoffe, ich konnte mein Problem verständlich machen.

Mit freundlichen Grüßen

Turps
 

German

Well-Known Member
c-b Experte
#2
Ich habe pthreads zwar nicht auf meiner Windows Kiste, aber ich sehe das auch so, dass du ein struct anlegen musst und zusätzlich noch eine Threadfunktion.

Das struct könnte etwa so aussehen:
C:
struct threadarg
{
  pthread_t thread_id;
  int (*op)(int, int);
  int *data;
  int len;
  int ret;
};
Deine Threadfunktion:
C:
void *start_routine(void *p_arg)
{
  struct threadarg *arg_ptr = p_arg;
  // hier mit arg_ptr arbeiten und dem ret Member das Ergebnis zuweisen
  return NULL;
}
In deiner parallel_reduce:
C:
  struct threadarg args[MAX_THREAD] = {0};

  for (int i = 0; i < MAX_THREAD; ++i)
  {
    // weise hier den args[i] Members die Werte von op, data und len für den Thread zu ...
    // ...
    if (pthread_create(&args[i].thread_id, NULL, start_routine, &args[i]) != 0)
    {
      // Fehlerbehandlung
    }
  }
  // ...
So etwa würde ich rangehen.
 

Turps

New Member
#4
Habe es leider nicht gänzlich hinbekommen.
Das ist die Lösung unseres Tutors. Vielleicht hilft das ja jemanden.

C++:
#include <stdio.h>

#include <pthread.h>

#define NUM_THREADS 2

struct Param {
  int (*op)(int, int);
  int *data;
  int len;
  int *result;
};

int max(int a, int b)
{
  return (a>b) ? a : b;
}

int sum(int a, int b)
{
  return a+b;
}

int reduce(int (*op)(int, int),
           int *data,
           int len)
{
  int i;
  int result = data[0];
  for (i = 1; i < len; ++i)
    result = op(result, data[i]);
  return result;
}

void *reduce_wrapper(void *param)
{
  struct Param* p = (struct Param*)param;
  int result = reduce(p->op, p->data, p->len);
  *(p->result) = result;
}

int parallel_reduce(int (*op)(int, int),
                    int *data,
                    int len)
{
  int t;
  pthread_t threads[NUM_THREADS];
  struct Param params[NUM_THREADS];
  int results[NUM_THREADS];

  for (t = 0; t < NUM_THREADS; ++t) {
    params[t].op      = op;
    params[t].data    = data + (len/NUM_THREADS) * t;
    params[t].len     = len / NUM_THREADS;
    params[t].result  = &results[t];

    pthread_create( &threads[t], NULL, reduce_wrapper, &params[t] );
  }
  for (t = 0; t < NUM_THREADS; ++t) {
    pthread_join( threads[t], NULL );
  }
  return reduce(op, results, NUM_THREADS);
}

int main() {
  int data[] = {1,2,3,4,5,6,7,8,9,10};

  int m  = reduce(max, data, 10);
  int s = reduce(sum, data, 10);

  printf("max : %i; sum: %i\n", m, s);

  int pm = parallel_reduce(max, data, 10);
  int ps = parallel_reduce(sum, data, 10);

  printf("parallel max : %i; parallel sum: %i\n", pm, ps);
  return 0;
}
 
Oben