• Nenhum resultado encontrado

Threads Windows

No documento Fundamentos de Sistemas Operacionais (páginas 162-166)

A  técnica  de  criação  de  threads  com  o  uso  da  biblioteca  de  threads  Windows  é  semelhante  à  técnica  do Pthreads em vários aspectos. Ilustramos a API de threads Windows no programa em C mostrado na Figura 4.11. Observe que devemos incluir o arquivo de cabeçalho windows.h ao usar a API Windows.

Como na versão do Pthreads mostrada na Figura 4.9, os dados compartilhados por threads separados − nesse caso, Sum − são declarados globalmente (o tipo de dado DWORD é um inteiro de 32 bits sem sinal). Também  definimos  a  função Summation ( ) que  deve  ser  executada  em  um  thread  separado.  Essa função recebe um ponteiro para um tipo void, que o Windows define como LPVOID. O thread que executa essa função define a soma de dados global Sum como o resultado da soma dos valores de 0 até o parâmetro passado para Summation ( ).

#define NUM_THREADS 10

/* um array de threads para o agrupamento */ pthread_t workers[NUM THREADS];

for (int i = 0; i < NUM_THREADS; i++)   pthread_join(workers[i], NULL);

Figura 4.10 Código Pthread para o agrupamento de dez threads.

Os threads são criados na API Windows com o uso da função CreateThread ( ), e  —  como  no Pthreads  —  um  conjunto  de  atributos  do  thread  é  passado  para  essa  função.  Esses  atributos  incluem informações de segurança, o tamanho da pilha e um flag que pode ser posicionado para indicar se o thread deve  ser  iniciado  em  estado  de  suspensão.  Nesse  programa,  usamos  os  valores  default  desses  atributos. (Inicialmente, os valores default não estabelecem um estado de suspensão para o thread e, em vez disso, o tornam elegível para ser executado pelo scheduler da CPU.) Uma vez que o thread de soma seja criado, o pai deve esperar que ele seja concluído antes de exibir o valor de Sum, já que o valor é definido pelo thread de soma. Lembre­se de que, no programa Pthread (Figura 4.9), o thread­pai espera pelo thread de soma usando o  comando  pthread_join ( ).  Fizemos  algo  semelhante  na  API  Windows  usando  a  função WaitForSingleObject ( ), que causa o bloqueio do thread criador até que o thread de soma tenha sido encerrado.

Em  situações  que  requerem  a  espera  da  conclusão  de  múltiplos  threads,  a  função WaitForMultipleObjects ( ) é usada. Essa função recebe quatro parâmetros: O número de objetos que estão sendo esperados Um ponteiro para o array de objetos Um flag indicando se todos os objetos foram sinalizados Um tempo limite (ou INFINITE) Por exemplo, se THandles é um array de objetos thread HANDLE de tamanho N, o thread­pai pode esperar que todos os seus threads­filhos sejam concluídos com esse comando:

WaitForMultipleObjects (N, THandles, TRUE, INFINITE)

Threads Java

Os threads são o modelo básico de execução de programas em Java, e a linguagem Java e sua API fornecem um rico conjunto de recursos para a criação e o gerenciamento de threads. Todos os programas em Java são compostos por, pelo menos, um thread de controle — até mesmo um programa em Java simples, composto por  apenas  um  método main ( ),  é  executado  como  um  único  thread  na  JVM.  Os  threads  Java  estão disponíveis em qualquer sistema que forneça uma JVM, incluindo o Windows, o Linux e o MacOS X. A API de threads Java também está disponível para aplicações do Android.

Há duas técnicas para a criação de threads num programa em Java. Uma abordagem é a criação de uma nova classe derivada da classe Thread e a sobreposição de seu método run ( ). Uma técnica alternativa —  e  mais  usada  —  é  a  definição  de  uma  classe  que  implementa  a  interface Runnable.  A  interface Runnable é definida como descrito a seguir:

public interface Runnable {

public abstract void run (); }

Quando  uma  classe  implementa Runnable,  ela  deve  definir  um  método  run ( ).  O  código  que implementa o método run ( ) é o que é executado como um thread separado.

#include <windows.h> #include <stdio.h>

DWORD Sum; /* os dados são compartilhados pelo(s) thread(s) */ /* o thread é executado nessa função separada */

DWORD WINAPI Summation(LPVOID Param) {

  DWORD Upper = *(DWORD*)Param;   for (DWORD i = 0; i <= Upper; i++)     Sum += i;

  return 0; }

int main(int argc, char *argv[]) {

  DWORD ThreadId;   HANDLE ThreadHandle;   int Param;

  if (argc != 2) {

    fprintf(stderr,”An integer parameter is required\n”);     return -1;

  }

  Param = atoi(argv[1]);   if (Param < 0) {

    fprintf(stderr,”An integer >= 0 is required\n”);     return -1;

  }

  /* cria o thread*/

  ThreadHandle = CreateThread(

    NULL, /* atributos default de segurança */     0, /* tamanho default de pilha */

    Summation, /* função do thread */

1. 2.

    0, /* flags default de criação */

    &ThreadId); /* retorna o identificador do thread */   if (ThreadHandle != NULL) {

    /* agora espera que o thread seja encerrado */     WaitForSingleObject(ThreadHandle,INFINITE);     /* fecha o manipulador do thread */

    CloseHandle(ThreadHandle);     printf(“sum = %d\n”,Sum);   }

}

Figura 4.11 Programa em C com múltiplos threads usando a API Windows.

A Figura 4.12  mostra  a  versão  Java  de  um  programa  com  múltiplos  threads  que  determina  a  soma  de inteiros  não  negativos.  A  classe Summation implementa a interface Runnable.  A  criação  de  threads  é executada  com  a  criação  de  uma  instância  de  objeto  da  classe Thread  e  a  passagem  de  um  objeto Runnable para o construtor.

A  criação  de  um  objeto Thread não  cria,  especificamente,  o  novo  thread;  em  vez  disso,  é  o  método start ( ) que cria o novo thread. A chamada do método start ( ) do novo objeto faz duas coisas:

Aloca memória e inicializa um novo thread na JVM.

Chama o método run ( ), tornando o thread elegível para execução na JVM. (Observe, mais uma vez, que nunca chamamos o método run ( ) diretamente. Em vez disso, chamamos o método start ( ) que chama o método run ( ) em nosso nome.)

Quando o programa de soma é executado, a JVM cria dois threads. O primeiro é o thread­pai, que começa a execução no método main ( ). O segundo thread é criado quando o método start ( ) é invocado no objeto Thread. Esse thread­filho começa a execução no método run ( ) da classe Summation. Após dar saída no valor da soma, o thread termina ao sair de seu método run ( ).

O compartilhamento de dados entre threads ocorre facilmente no Windows e no Pthreads porque os dados compartilhados  são  simplesmente  declarados  como  globais.  Já  que  é  totalmente  orientada  a  objetos,  a linguagem Java não tem o conceito de dados globais. Se dois ou mais threads precisam compartilhar dados em um programa em Java, o compartilhamento ocorre pela passagem de referências do objeto compartilhado para os threads apropriados. No programa em Java mostrado na Figura 4.12, o thread principal e o thread de soma  compartilham  a  instância  de  objeto  da  classe Sum.  Esse  objeto  compartilhado  é  referenciado  pelos métodos getSum ( ) e setSum ( ) apropriados. (Você deve estar se perguntando por que não usamos um objeto Integer em vez de projetar uma nova classe Sum. O motivo é que a classe Integer é imutável — isto é, uma vez que seu valor seja estabelecido, ele não pode mudar.)

Você deve lembrar que os threads­pais das bibliotecas Pthreads e Windows usam pthread_join ( ) e WaitForSingleObject ( ) (respectivamente) para esperar que os threads de soma terminem antes de prosseguir. O método join ( ) em Java fornece funcionalidade semelhante. (Observe que join ( ) pode lançar uma InterruptedException, que preferimos ignorar.) Se o pai deve esperar que múltiplos threads terminem, o método join ( ) pode ser inserido em um loop for semelhante ao mostrado para o Pthreads na Figura 4.10.

class Sum {

  private int sum;   public int getSum() {

    return sum;   }

  public void setSum(int sum) {     this.sum = sum;

  } }

class Summation implements Runnable {

  private int upper;   private Sum sumValue;

  public Summation(int upper, Sum sumValue) {     this.upper = upper;

    this.sumValue = sumValue;   }

  public void run() {     int sum = 0;

    for (int i = 0; i <= upper; i++)       sum += i;

    sumValue.setSum(sum);   }

}

public class Driver {

  public static void main(String[] args) {     if (args.length > 0) {

      if (Integer.parseInt(args[0]) < 0)

        System.err.println(args[0] + “ must be >= 0.”);       else {

        Sum sumObject = new Sum();

        int upper = Integer.parseInt(args[0]);

        Thread thrd = new Thread(new Summation(upper, sumObject));         thrd.start();

        try {

      thrd.join();

      System.out.println

      (“The sum of “+upper+” is “+sumObject.getSum());       } catch (InterruptedException ie) { }

    }   }   else

    System.err.println(“Usage: Summation <integer value>”); } }

Figura 4.12 Programa em Java para a soma de inteiros não negativos.

4.5

4.5.1

1. 2.

A JVM costuma ser implementada no topo de um sistema operacional hospedeiro (consulte a Figura 16.10).  Essa  configuração  permite  que  a  JVM  oculte  os  detalhes  de  implementação  do  sistema operacional  subjacente  e  forneça  um  ambiente  abstrato  e  consistente  que  permita  aos  programas Java operarem em qualquer plataforma que suporte a JVM. A especificação da JVM não indica como os threads Java devem ser mapeados para o sistema operacional subjacente, deixando essa decisão a cargo da implementação específica da JVM. Por exemplo, o sistema operacional Windows XP usa o  modelo  um­para­um;  assim,  cada  thread  Java  de  uma  JVM,  sendo  executada  nesse  sistema,  é mapeado  para  um  thread  do  kernel.  Em  sistemas  operacionais  que  usam  o  modelo  muitos­para­ muitos (como o Tru64 UNIX), um thread Java é mapeado de acordo com tal modelo. Inicialmente, o Solaris  implementava  a  JVM  usando  o  modelo  muitos­para­um  (a  biblioteca  green  threads, mencionada  anteriormente).  Versões  posteriores  da  JVM  foram  implementadas  usando  o  modelo muitos­para­muitos. A partir do Solaris 9, os threads Java começaram a ser mapeados com o uso do modelo um­para­um. Além disso, pode haver um relacionamento entre a biblioteca de threads Java e a biblioteca  de  threads  do  sistema  operacional  hospedeiro.  Por  exemplo,  implementações  de  uma JVM para a família de sistemas operacionais Windows podem usar a API Windows ao criar threads Java; os sistemas Linux, Solaris e Mac OS X podem usar a API Pthreads.

No documento Fundamentos de Sistemas Operacionais (páginas 162-166)