Archive

Posts Tagged ‘processes’

Erlang hints

June 7, 2010 Leave a comment

Erlang is a wonderful tool…but sometimes it is awkward to manage your stuff (processes or ets/mnesia tables) just by using the shell. Let’s see how to exploit Erlang modules to make our lifes easier!

Many times I was looking for a specific Erlang process using one of the bifs you can see below:

1> registered().
[init,global_group,erl_prim_loader,user,error_logger,rex,
 standard_error_sup,kernel_sup,global_name_server,inet_db,
 file_server_2,code_server,user_drv,application_controller,
 standard_error,kernel_safe_sup]

Or

2> processes().
[<0.0.0>,<0.3.0>,<0.5.0>,<0.6.0>,<0.8.0>,<0.9.0>,<0.10.0>,
 <0.11.0>,<0.12.0>,<0.13.0>,<0.14.0>,<0.15.0>,<0.16.0>,
 <0.17.0>,<0.18.0>,<0.19.0>,<0.20.0>,<0.21.0>,<0.22.0>,
 <0.23.0>,<0.24.0>,<0.25.0>,<0.26.0>,<0.27.0>,<0.28.0>,
 <0.34.0>]

For me it can be painful to use this kind of approach, so I geeked around to search some new ways to follow processes; here are two useful modules I found.

The first one is etop, a module which works pretty much as the unix application etop.

4> etop:start([{output, text}]).  

========================================================================================
 nonode@nohost                                                             08:26:31
 Load:  cpu         0               Memory:  total        3961    binary         13
        procs      27                        processes     582    code         1888
        runq        0                        atom          294    ets           132

Pid            Name or Initial Func    Time    Reds  Memory    MsgQ Current Function
----------------------------------------------------------------------------------------
<0.3.0>        erl_prim_loader          '-'  265995   23512       0 erl_prim_loader:loop
<0.19.0>       code_server              '-'  109125   71224       0 code_server:loop/1
<0.34.0>       etop_server              '-'    7164   21072       0 etop:data_handler/2
<0.6.0>        application_controll     '-'    6931  212992       0 gen_server:loop/6
<0.26.0>       erlang:apply/2           '-'    5151   17184       0 shell:shell_rep/4
<0.0.0>        init                     '-'    2501    8316       0 init:loop/1
<0.25.0>       group:server/3           '-'    1820   12304       0 group:server_loop/3
<0.10.0>       kernel_sup               '-'    1289    6096       0 gen_server:loop/6
<0.23.0>       user_drv                 '-'    1278    9308       0 user_drv:server_loop
<0.27.0>       proc_lib:init_p/5        '-'     268    1372       0 gen_server:loop/6
========================================================================================

The second is the bif regs():

2> regs().

** Registered procs on node nonode@nohost **
Name                  Pid          Initial Call                      Reds Msgs
application_controlle <0.6.0>      erlang:apply/2                     444    0
code_server           <0.19.0>     erlang:apply/2                  104722    0
erl_prim_loader       <0.3.0>      erlang:apply/2                  167826    0
error_logger          <0.5.0>      gen_event:init_it/6                226    0
file_server_2         <0.18.0>     file_server:init/1                  86    0
global_group          <0.17.0>     global_group:init/1                 60    0
global_name_server    <0.12.0>     global:init/1                       53    0
inet_db               <0.16.0>     inet_db:init/1                     130    0
init                  <0.0.0>      otp_ring0:start/2                 2450    0
kernel_safe_sup       <0.28.0>     supervisor:kernel/1                 57    0
kernel_sup            <0.10.0>     supervisor:kernel/1               1289    0
rex                   <0.11.0>     rpc:init/1                          36    0
standard_error        <0.21.0>     standard_error:server/2              7    0
standard_error_sup    <0.20.0>     supervisor_bridge:standar           40    0
user                  <0.24.0>     group:server/3                      38    0
user_drv              <0.23.0>     user_drv:server/2                  625    0

** Registered ports on node nonode@nohost **
Name                  Id              Command
ok

The third is pman, a graphical process manager very useful to inspect the Erlang processes executing either locally or on remote nodes. It is also possible to trace events in the individual processes.

3> pman:start().

pman on windows7

And that was for processes! But, since many times you have also to work with Mnesia/ets tables, I think that this can be also useful to you. Let’s say you want to see what tables you have in your system, in this case you will probably use:

1> ets:all().
[8207,4110,13,file_io_servers,inet_hosts_file_byaddr,
 inet_hosts_file_byname,inet_hosts_byaddr,inet_hosts_byname,
 inet_cache,inet_db,global_pid_ids,global_pid_names,
 global_names_ext,global_names,global_locks,ac_tab]

Well. I suggest you to use tv, that graphically examines ETS and Mnesia tables

tv on windows7

That was all! Stay tuned!

Categories: English, Erlang Tags: , ,

Semaphores in C

November 13, 2009 Leave a comment

Quando si parla di processi in C, è utile introdurre il concetto di SEMAPHORES. Un semaphore in informatica viene utilizzato pe gestire l’accesso ad una risorsa condivisa e viene implementato sulla base di un valore intero e di due primitive: UP e DOWN.

Posto che il valore dell’intero venga identificato con V, allora:

  • se V > 0 un’operazione di DOWN ne abbassa il valore di un’unità
  • se V = 0 un’operazione di DOWN viene messa in attesa finchè V > 0 e poi ne abbassa il valore di un’unità
  • un’operazione di UP aumenta il valore di V di un’unità

Un semaforo in C può essere creato utilizzando la seguente sintassi:

key_t key; //key
int sem_id; //semaphore id
int nsems = 10; //number of semaphores in the set

key = ftok("/home/belleforonte/aaa", 7);
sem_id = semget(key, nsems, 0666|IPC_CREAT); // last one is (access rights | create/re-use)

La variabile key rappresenta una chiave e viene creata tramite il comando ftok(const char *pathname, int proj_id); dove pathname indica il percorso di un file ESISTENTE (su una directory in cui dovete avere diritti di accesso) mentre proj_id è un intero che rappresenta un id.

Dopo aver creato la chiave, andiamo ad utilizzarla nella creazione/riutilizzo di un semaforo usando il comando

semget(key_t key, int nsems, int semflg); è da notare che un precedente semaforo avrebbe potuto essere reutilizzato tramite il comando semget(key, 0, 0) dove la key avrebbe dovuto essere stata la stessa utilizzata per la creazione.

La funzione vista in precedenza ritorna -1 se non può essere eseguita correttamente, dunque se il semaphore set non è stato creato.

Semaphore

Dopo aver creato il semaphore passiamo a capire come manipolarlo tramite le operazioni di UP e DOWN.

Per effettuare operazioni con un semaphore set facciamo qualcosa di simile:

int semop(int sem_id, struct sembuf *sops, unsigned nsops);

Dove: sem_id è il valore ottenuto dal comando semget, sops è un array di comandi sul semaphore identificati da una struttura del tipo:

struct sembuf {
  u_short sem_num; // indicates which one is the semaphore to control
  short sem_op; // indicate which one is the variable to increment/decrement
  short sem_flag;
}

mentre nsops è il numero di comandi nell’array.

Nella struttura sembuf: sem_num indica il numero del semaphore nel set, sem_op indica l’operazione da eseguire, mentre sem_flg
 dovrebbe essere posta a 0.

Il semaforo viene  comandato in base al valore di sem_op, infatti
:

  • se 
sem_op
 >
 0,
 il valore del semaphore viene aumenta di sem_op
  • se sem_op
<
0
  • o se il valore del semaphore è maggiore o uguale
 al valore assoluto di sem_op, il valore del semaphore è diminuito di sem_op e poi l’esecuzione del codice continua

    o se il valore del semaphore è minore del valore assoluto di sem_op,
 l’esecuzione è sospesa finchè un altro processo non incrementa il valore del semaphore

  • se sem_op = 0, l’esecuzione è sospesa finchè il semaforo è a valore 0

Prima di vedere un esempio concreto ricordo che è FONDAMENTALE eliminare i semaphores se non si usano più. Questa procedura viene eseguita nel seguente modo:

int semctl(sem_id, 0, IPC_RMID);

Inoltre i seguenti comandi da linea di comando possono essere utili, il primo per vedere i semafori attivi e il secondo per rimuoverne uno: sotto posto il codice per vederne il man:

bellerofonte@pegaso:~$ man ipcs
.....man di ipcs
bellerofonte@pegaso:~$ man ipcrm
.....man di ipcrm

Passiamo ora a vedere l’esempio del producer-consumer.

Cito Wikipedia:

“In informatica, il problema del produttore-consumatore (conosciuto anche con il nome di problema del buffer limitato o bounded-buffer problem) è un esempio classico di sincronizzazione tra processi. Il problema descrive due processi, uno produttore (in inglese producer) ed uno consumatore (consumer), che condividono un buffer comune, di dimensione fissata. Compito del produttore è generare dati e depositarli nel buffer in continuo. Contemporaneamente, il consumatore utilizzerà i dati prodotti, rimuovendoli di volta in volta dal buffer. Il problema è assicurare che il produttore non elabori nuovi dati se il buffer è pieno, e che il consumatore non cerchi dati se il buffer è vuoto.

La soluzione per il produttore è sospendere la propria esecuzione se il buffer è pieno; non appena il consumatore avrà prelevato un elemento dal buffer, esso “sveglierà” il produttore, che ricomincerà quindi a riempire il buffer. Allo stesso modo, il consumatore si sospenderà se il buffer è vuoto; non appena il produttore avrà scaricato dati nel buffer, risveglierà il consumatore. Questa soluzione può essere implementata tramite delle strategie di comunicazione tra processi, tipicamente con dei semafori. Una soluzione errata potrebbe dar luogo ad un deadlock, in cui entrambi i processi aspettano di essere risvegliati.”

Ecco una possibile implementazione del producer:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
  key_t key = ftok("/home/belleforonte/Desktop/a", 1);//file a must exist(can be any file)
  int sem_id = semget(key, 1, 0666 | IPC_CREAT);
  getchar();

  struct sembuf sops = {
    .sem_num = 0,
    .sem_op = 1 // increment by one
  };

  semop(sem_id, &sops, 1);
}

E del  consumer:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
  key_t key = ftok("/home/belleforonte/Desktop/a", 1);//file a must exist(can be any file)
  int sem_id = semget(key, 0, 0);

  struct sembuf sops = {
    .sem_num = 0,
    .sem_op = -1 // decrease by one
  };

  semop(sem_id, &sops, 1);
  printf("Key pressed\n");
}

Finito! 🙂

Categories: C Tags: ,

Pipes in C

November 12, 2009 Leave a comment

Il mio pc è ancora defunto..quindi anche oggi vi parlerò di C e non di Erlang 😦

Oggi tratterò le PIPES in C. Le pipes sono utilizzate per garantire un canale di comunicazione tra processi diversi e proprio come la traduzione di PIPE dall’inglese suggerisce, possono essere viste come un “tubo” con un foro di ingresso e uno di uscita.

Le PIPEs vengo gestite tramite due descrittori di file: uno viene usato per la scrittura e l’atro per la lettura di dati. Una PIPE viene dichiarata nel seguente modo:

int fd[2];
pipe(fd);

La prima riga introduce un array di 2 elementi che verranno usati come file descriptors, mentre la seconda va a creare una PIPE caratterizzata da tali descriptors.

Vediamo una un codice in cui dopo la creazione della PIPE verrà eseguito un fork: il processo figlio scriverà sulla PIPE, mentre il processo padre leggerà da essa.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
  int fd[2], nbytes;
  pid_t pid;
  char string[] = "Hello world!\n";
  char readbuffer[80];

  pipe(fd);

  switch(pid = fork())
    {
    case -1:
      printf("Error in fork() command\n");
      close(fd[0]);
    case 0:
      close(fd[0]);
      write(fd[1], string, 13);
      _exit(0);
    default:
      close(fd[1]);
      nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
      printf("Received string: %s", readbuffer);
    }
  return(0);
}

Il codice come potete vedere inizia con l’inclusione di alcune librerie che ci saranno utili, in seguito vengono dichiarate le variabili, alcune allo scopo di utilizzare la PIPE, altre per la lettura e la scrittura di stringhe sulla PIPE stessa.

Dopo aver creato la PIPE eseguiamo il fork e ne switchiamo il risultato: in caso di processo padre andiamo a leggere il valore presente in fd[0] (SEMPRE E SOLO UTILIZZATO PER LA LETTURA), assegniamo tale valore alla variabile readbuffer e ne stampiamo il valore a video.

In caso di processo figlio invece scriviamo il valore della variabile string in fd[1] che viene SEMPRE USATO PER LA SCRITTURA e poi terminiamo il processo.

Categories: C Tags: , ,