Skoči na vsebino

Podatki v skupnem pomnilniku

Program in vse niti programa vidijo celotni pomnilnik ne glede na to, kako je pomnilnik fizično organiziran. Kljub temu pa so nekateri deli pomnilnika dodeljeni celemu programu in torej vsem nitim, drugi deli pa so dodeljeni posebej posameznim nitim.

Na tem mestu velja opozorilo, da posebne zaščite pri dodoeljevanju pomnilnika posameznim nitim ni, programer mora pač paziti, da ne krši pravil, ki programskega jezika C in orodja OpenMP.

Skupne in zasebne spremenljivke

Spremenljivke v programu glede na programski jezik C obdržijo svoje lastnosti, orodje OpenMP pa doda še delitev na skupne in zasebne spremenljivke:

  • Skupna spremenljivka je spremenljivka, ki si jo delijo vse niti posamezne skupine.
    Če v programu ni določeno drugače, so

    • vse globalne spremenljivke,
    • vse statične lokalne spremenljivke in
    • vse lokalne spremenljivke zunaj območij nitenja

    skupne. Prav tako so vsi dinamično dodeljeni pomnilniški bloki skupni.

  • Zasebna spremenljivka je lastna posamezni niti.
    Če v programu ni določeno drugače, so

    • vse avtomatske lokalne spremenjivke v območjih gnezdenja in
    • vse avtomatske lokalne spremenljivke in parametri funkcij, ki so bile klicane iz območij nitenja,

    zasebne spremenljivke lastne posamezni niti.

Kaj ta delitev pomeni, si oglejmo z nekaj primeri. Najprej si oglejmo program, ki izpiše pomnilniške naslove svojih spremenljivk:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>
#include <omp.h>

int main ()
{
  int shared_var;
  printf ("shared:%p\n", &shared_var);
  #pragma omp parallel
  {
    int private_var;
    printf ("%2d:   shared:%p private:%p\n",
            omp_get_thread_num (), &shared_var, &private_var);
  }
  return 0;
}

Iz pomnilniških naslovov v izpisu vidimo, da v času izvajanja obstaja ena sama skupna spremenljivka shared_var, a več zasebnih spremenljivk private_var, po ena v vsaki niti:

env OMP_NUM_THREADS=2 ./data-1
shared:0x7fff5f7fcc84
0:   shared:0x7fff5f7fcc84 private:0x7fff5f7fcc3c
1:   shared:0x7fff5f7fcc84 private:0x7fb93669ee2c
env OMP_NUM_THREADS=2 ./data-1

Vaja

Kljub temu, da zasebna spremenljivka lastna eni niti ni vidna v drugi niti, lahko iz druge niti še vedno dostopamo do nje. Kako?

Določanje deljenja dostopa do spremenljivk

Če pravila, ki določajo, ali je spremenljivka skupna ali zasebna, ne ustrezajo, lahko to za posamezno spremenljivko posebej določimo z dopolnili:

  • Dopolnilo private spremeni sicer skupno spremenljivko v zasebno.
    Zasebna spremenljivka (ali bolje vsaka zasebna spremenljivka znotraj posamezne niti) ni povezana s sicer skupno spremenljivko zunaj območja nitenja. Zato na začetku ni inicializirana, na koncu pa se njena vrednost ne prenese v skupno spremenljivko.
    Glej program data-private-1.c.
  • Dopolnilo firstprivate spremeni sicer skupno spremenljivko v zasebno, ki ob začetku nitenja prevzame vrednost skupne spremenljivke.
    Glej program data-firstprivate-1.c.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <omp.h>

int main ()
{
  int shared_var;
  int var = -1;
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  #pragma omp parallel private(var)
  {
    var = omp_get_thread_num ();
    printf ("%2d:   shared:%p private:%p %d\n",
            omp_get_thread_num (), &shared_var, &var, var);
  }
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <omp.h>

int main ()
{
  int shared_var;
  int var = 10;
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  #pragma omp parallel firstprivate(var)
  {
    var = var + omp_get_thread_num ();
    printf ("%2d:   shared:%p private:%p %d\n",
            omp_get_thread_num (), &shared_var, &var, var);
  }
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  return 0;
}

Vaja

Kljub temu, da zasebna spremenljivka lastna eni niti ni vidna v drugi niti, lahko iz druge niti še vedno dostopamo do nje. Kako?

Kadar se program večkrat zaporedoma razcepi v skupino niti, lahko ustvarimo zasebne spremenljivke posameznih niti, ki pripadajo večim zaporednim nitenjem. To dosežemo z ukazom #pragma omp threadprivate, s katerim za statično spremenljivko dosežemo, da je zasebna v posametnih nitih.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <omp.h>

int var = -1;
#pragma omp threadprivate(var)

int main ()
{
  int shared_var;
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  #pragma omp parallel
  {
    var = omp_get_thread_num ();
    printf ("1st %2d:   shared:%p private:%p %d\n",
            omp_get_thread_num (), &shared_var, &var, var);
  }
  #pragma omp parallel
  {
    printf ("2nd %2d:   shared:%p private:%p %d\n",
            omp_get_thread_num (), &shared_var, &var, var);
  }
  printf ("shared:%p private:%p %d\n", &shared_var, &var, var);
  return 0;
}