Helsingin yliopisto Tietojenkäsittelytieteen laitos
 

Tietojenkäsittelytieteen laitos

Tietoa laitoksesta:

 
Helsingin yliopisto / Tietojenkäsittelytieteen laitos / Copyright © 2001 Jan Lindström. Tämän oppimateriaalin käyttö on sallittu vain yksityishenkilöille opiskelutarkoituksissa. Materiaalin käyttö muihin tarkoituksiin, kuten kaupallisilla tai muilla kursseilla, on kielletty.

8. Säikeet


Prosessi on suoritusympäristö + useita säikeitä. Säien on käyttöjärjestelmän abstraktio aktiviteetista eli suorituspolusta. Suoritusympäristö on resurssinhallintayksikkö. Säikeellä omaa:

Säikeille yhteistä mm.:

POSIX vaatii käyttäjän määrittelevän muuttujan tyyppiä pthread_t, jonka avulla säie identifioidaan. Säie luodaan kutsulla:

int pthread_create(pthread_t *thread, pthread_attr_t *attr,
                   void *(*start_routine)(void *), void *arg);

Kutsun onnistuessa uuden säikeen tunnus tallenetaan parametriin thread ja funktio palauttaa arvon 0. Virhetilanteessa nollasta poikkeava arvo palautuu. Esimerkiksi jos luodaan säie suorittamaan funktiota f():

#include < pthread.h >
...
 pthread_t thread;
 pthread_create(&thread, NULL, f, &arg).
...

The routine f() must have the prototype:

void *f(void *arg);

Ohjelman viimeiseksi toimeksi täytyy odottaa kaikkien säikeiden päättymistä ennenkuin voi käsitellä funktion f() paluuarvoa. Odottaminen tapahtuu funktiolla:

int pthread_join(pthread_t th, void **thread_return);
Funktion kutsuja jää odottamaan kunnes säie, jonka identifikaation on th päättyy.

Nopein tapa välittää informaatiota säikeiden välillä on yhteinen muisti. Tämä kuitenkin vaatii synkronointia säikeiden välillä. Synkronointia varten tarvitaan erityinen synkronointimuuttuja, joka luodaan funktiolla:

int pthread_mutex_init(pthread_mutex_t  *mutex,
                       const pthread_mutexattr_t *mutexattr);

Esimerkiksi:


#include < pthread.h >
...
 pthread_mutex_t lock;
 pthread_mutex_init(&lock,NULL);
...
Esimerkki:

/* use gcc -lpthread to compile */

#include < stdio.h >
#include < pthread.h >

/* definition of a suitable structure */

typedef struct
{
  double volatile *p_s;       /* the shared value of scalar product */
  pthread_mutex_t *p_s_lock;  /* the lock for variable s */
  int n;                      /* the number of the thread */
  int nproc;                  /* the number of processors to exploit */
  double *x;                  /* data for first vector */
  double *y;                  /* data for second vector */
  int l;                      /* length of vectors */
} DATA;

void *SMP_scalprod(void *arg)
{
  register double localsum;
  long i;
  DATA D = *(DATA *)arg;

  localsum = 0.0;

/* Each thread start calculating the scalar product from i = D.n
   with D.n = 1, 2, ... , D.nproc.
   Since there are exactly D.nproc threads the increment on i is just
   D.nproc */

  for(i=D.n;i < D.l;i+=D.nproc)
     localsum += D.x[i]*D.y[i];

/* the thread assert the lock on s ... */
  pthread_mutex_lock(D.p_s_lock);

/* ... change the value of s ... */
  *(D.p_s) += localsum;

/* ... and remove the lock */
  pthread_mutex_unlock(D.p_s_lock);

  return NULL;
}

#define L 9    /* dimension of vectors */

int main(int argc, char **argv)
{
  pthread_t *thread;
  void *retval;
  int cpu, i;
  DATA *A;
  volatile double s=0;     /* the shared variable */
  pthread_mutex_t s_lock;
  double x[L], y[L];

  if(argc != 2)
    {
      printf("usage: %s  \n", argv[0]);
      exit(1);
    }

  cpu = atoi(argv[1]);
  thread = (pthread_t *) calloc(cpu, sizeof(pthread_t));
  A = (DATA *)calloc(cpu, sizeof(DATA));


  for(i=0;i < L;i++)
    x[i] = y[i] = i;

/* initialize the lock variable */
  pthread_mutex_init(&s_lock, NULL);

  for(i=0;i < cpu;i++)
    {
/* initialize the structure */
      A[i].n = i;            /* the number of the thread */
      A[i].x = x;
      A[i].y = y;
      A[i].l = L;
      A[i].nproc = cpu;      /* the number of CPU */
      A[i].p_s = &s;
      A[i].p_s_lock = &s_lock;

      if(pthread_create(&thread[i], NULL, SMP_scalprod, &A[i] ))
        {
          fprintf(stderr, "%s: cannot make thread\n", argv[0]);
          exit(1);
        }
    }

  for(i=0;i < cpu;i++)
    {
      if(pthread_join(thread[i], &retval))
        {
          fprintf(stderr, "%s: cannot join thread\n", argv[0]);
          exit(1);
        }
    }

  printf("s = %f\n", s);
  exit(0);
}


Jan Lindström (Jan.Lindstrom@cs.Helsinki.FI)