Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

alves077

[Dúvida] Thread

Mensagens Recomendadas

alves077

Boa noite,

Tenho aqui dúvida em relação as thread terem os dados partilhados entre si que ainda não percebo muito bem.

Podem surgir erros na execução quando uma thread acede à stack de outra thread?

Obrigado pela atenção,

alves077

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

Eu não me lembro de existir acesso ao stack de uma outra thread... Só me lembro é da heap ser partilhada e não a stack.

Aliás, como é que achas que conseguias que uma thread estivesse numa função e outra thread noutra função, ao mesmo tempo, se partilhassem a stack?


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

É seguindo o ideia que é possível uma thread aceder a variáveis presentes na stack de outra thead, que me surgiu esta dúvida...

Isto em programação multi-thread como é claro.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
eatg75

Oi boa noite.

Se estiveres a falar das POSIX Threads, as duas threads criadas dentro de um mesmo processo partilham variaveis globais, descritores de ficheiros, diretoria corrente, instrucoes a executar (mas, cada thread tem a sua Program Counter)..., mas nao partilham registros, stack (mesmo se estao a executar a mesmo funcao, cada uma tem a sua stack com as suas variaveis locais, parametros), errno, etc.

Respondendo a tua questao, NAO duas threads nao partilham a mesma stack.

Se fores realmente curioso e com vontade de aprender le estes dois livros (apenas a parte que precisares)

http://www.amazon.com/Programming-POSIX-Threads-David-Butenhof/dp/0201633922

http://www.amazon.com/UNIX-Network-Programming-Volume-Communications/dp/0130810819/ref=pd_sim_b_4


Victarion seized the dusky woman by the wrist and pulled her to him.

Victarion - She will do it. Go pray to your red god. Light your fire, and tell me what you see.

Moqorro's dark eyes seemed to shine.

Moqorro - I see dragons.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

Se não estou em erro, partilham as variáveis da stack que foram criadas antes das threads serem lançadas. (Corrijam-me se estiver enganado, não uso muito threads ultimamente.)

Mesmo assim, não.

Já usei POSIX threads e não partilham variáveis assim.

Uma thread é criada e iniciada com uma chamada a uma função indicada.

Tanto quanto sei, é como o eatg75 afirmou.


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Rui Carlos

Aquilo que queria dizer é que ao criares uma nova thread, há uma nova stack a partir daí. O que está para trás não é duplicado (e alterações nessa parte, seriam visíveis por ambas as threads).

Mas na verdade isto é irrelevante, pois não vamos mexer nesse scope dentro da thread. No máximo podemos passar um apontador à nova thread, mas aqui não faz muito sentido dizer que estamos a aceder a uma variável partilhada (é um simples apontador, que por acaso pode apontar para a stack de outra thread).

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
NuGuN

Boas!

Sim, o eatg75 está correto. Cada thread tem a sua stack. O que não quer dizer que seja impossível uma thread aceder à stack de uma outra thread. já a heap é comum tanto à main thread como a "worker threads". Esta acaba por ser mais lenta, não por ser comum mas pela forma como a memória é acedida.

Geralmente antes da main thread iniciar as worker threads ha a possibilidade de ser criara uma área de memória partilhada, e quando as worker threads são criadas é-lhes passado um apontador para essa área. Esta será a forma mais simples de partilhar informação entre elas.

Cumps!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

Hm.. ok

Mesmo cada thread tendo a sua stack, pudendo eu a partir de uma thread aceder á stack de outra thread , que tipo de problema posso ter?

Isto é, posso ter problemas de sincronização, ler uma variavel da stack de outra thread, enquanto ela escreve nessa variavel pode criar inconsistência de dados, são estes tipos de problemas que podem acontecer entre leituras de stack de thread diferentes? Não sei sem fiz entender..

Obrigado pela atenção,

alves077

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
NuGuN

Sim, esse é um problema comum. Agora os problemas podem mudar dependendo de como e onde estás a aceder na stack... Dado o tipo de informação que é guardada na stack, não é boa ideia utilizar a stack para partilhar informação.

Cumps!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

Ok, obrigado.

No seguinte desta dúvida surgiu-me outra..

Uma função é thread-safe quando pode ser executada por várias thread's concorrentemente. Que tipo de restrições essa função precisa de ter?

Isto é, imaginemos que tenho uma variável declarado como static int dentro da função e incremento esta variável dentro da função, esta função é thread-safe?

Obrigado pela atenção,

alves077

Editado por alves077

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Flinger

Se a variável é declarada dentro da função, então cada chamada da mesma função vai criar um novo "espaço" para a mesma, independente das outras chamadas.

(as terminologias não são as correctas, mas assim não há confusão). Logo é Thread-safe. Se apenas usares variáveis locais e argumentos, então a tua função é thread-safe.

Verdade para tudo menos para as static :P Sorry. Pensei que a word static só tivesse a função de não permitir que as variáveis/funções fossem usadas fora do ficheiro onde são declaradas. Afinal quando usadas dentro de funções, mantêm o valor entre invocações, logo não é thread safe.

Editado por Flinger

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

Isto é, imaginemos que tenho uma variável declarado como static int dentro da função e incremento esta variável dentro da função, esta função é thread-safe?

Não.


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

Ok, Obrigado Flinger e brunoais. Mesmo só trabalhando com locais e parametros não existe a possibilidade não ser thread safe, por exemplo


void calc_vat(float *param, int size, float **ret_val) {
float *temp_array = malloc(sizeof(float)*size);
int i;
for (i = 0; i < size; i++)
 temp_array[i] = param[i]*(VAT+1);
*ret_val = temp_array;
}

Esta função para vocês é thread safe?

Estou na dúvida, mas não alterando nenhuma variável global fica na dúvida...

Obrigado pela atenção,

alves077

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

Hm... por ser ponteiros vão estar a alterar, assim sendo outras thread estão a apontar para a mesma zona de memoria, se um altera todos vêm os dados alterados, logo incoerência de dados?

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

o problema não é ver a alteração, mas sim acessos (seja de leitura ou escrita) por diferentes threads ao mesmo tempo.

não existe problema que se veja a alteração dos dados desde que cada operação ou total da operação (de leitura ou escrita) seja garantidamente efectuada sem "sobreposição" de tempos de execução.

vê este caso:

imagina que tens

- um array com 3 elementos (1, 2, 3)

- uma função que soma a cada elemento, o valor do elemento anterior.

int * array = {1, 2, 3};

void f(int * array, size_t array_size)
{
 int i = 1;
 for (; i < array_size; i++)
   array[i] += array[i - 1];
}

agora executas a mesma função em dois threads diferentes:

o resultado final deveria ser:

fim da primeira execução da função : {1, 3(1+2), 6(3+3)}

fim da segunda execução da função : {1, 4(1+3), 10(4+6)}

no fim da execução dos thread, o resultado deverá ser : {1, 4, 10}

no entanto, nada te garante que código é executado num determinado tempo.

podes muito bem ter este caso (assim como outros em que o resultado não é o esperado) :

                                 programa
                                    |
               <--------------------v
            thread 1
             criado
               >-----------------------------------------v
                                                      thread 2
                                                       criado
               v-----------------------------------------<
            thread 1
  array[1] = array[0] + array[1]
          (1, 3, 3)
               >-----------------------------------------v
                                                      thread 2
                                           array[1] = array[0] + array[1]
                                                     (1, 4, 3)
                                                         |               
                                                      thread 2
                                           array[2] = array[1] + array[2]
                                                     (1, 4, 7)
               v-----------------------------------------<
            thread 1
  array[2] = array[1] + array[2]
          (1, 4, 11)
               >--------------------v
                              resultado final
                                {1, 4, 11}
                                   !=
                                {1, 4, 10}

isto demonstra que a função não é thread-safe

regras simples : tudo que seja manipulação de dados em memória que não seja variáveis locais à função do thread não é thread-safe caso não exista nenhum sistema de sincronização ou exclusão de acesso (de leitura e escrita)

Editado por HappyHippyHippo

IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

@HappyHippyHippo Por mim, estás errado e o teu exemplo é inválido. Tratam-se de situações diferentes

void calc_vat(float *param, int size, float **ret_val) {
float *temp_array = malloc(sizeof(float)*size);
int i;
for (i = 0; i < size; i++)
 temp_array[i] = param[i]*(VAT+1);
*ret_val = temp_array;
}

Esta função para vocês é thread safe?

Para mim é thread-safe.

Não alteras dados da heap nem da stack que recebeste nos parâmetros e não mexes em variáveis globais. Só crias espaço novo e manipulas esse espaço novo.

Mesmo sendo thread-safe, só é thread-safe em relação a ela própria. Se andares a alterar o array noutro lado enquanto essa função estiver a trabalhar, é bem possível que obtenhas resultados inesperados.

Só para ser o mais claro possível, ao ser thread-safe, significa que podes executar essa função múltiplas vezes em simultâneo, não que podes executar essa e outra ao mesmo tempo, em que a outra altera, por exemplo, o array.


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

Para mim é thread-safe.

Só para ser o mais claro possível, ao ser thread-safe, significa que podes executar essa função múltiplas vezes em simultâneo, não que podes executar essa e outra ao mesmo tempo, em que a outra altera, por exemplo, o array.

temos conceitos diferentes de thread-safe

o meu é mais deste género

(wikipedia)

Thread safety is a computer programming concept applicable in the context of multi-threaded programs. A piece of code is thread-safe if it only manipulates shared data structures in a manner that guarantees safe execution by multiple threads at the same time. There are various strategies for making thread-safe data structures.

ser thread-safe é relevante a toda a aplicação/uso e não somente a sim mesmo como dizes aqui:

Mesmo sendo thread-safe, só é thread-safe em relação a ela própria. Se andares a alterar o array noutro lado enquanto essa função estiver a trabalhar, é bem possível que obtenhas resultados inesperados.

ps : nota que "ler" também pode ser considerado como "manipular"


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
alves077

Hm...

Só é thread safe se a função mexer com os dados da sua própria stack. Caso haja variaveis globais, por exemplo, tenho que garantir exclusão mútua para ser thread safe. Mas no caso de só ler não haveria problema, porque ninguem escreve nos dados logo não existe incoerencia dos dados?

Por exemplo,


void calc_vat(float *param, int size) {
float *temp_array = malloc(sizeof(float)*size);
int i;
for (i = 0; i < size; i++)
 temp_array[i] = param[i]*(VAT+1);
}

Assim já seria thread-safe?

Não escreve na variável, só há leitura de dados por isso não deve haver problema de várias thread acederem concorrentemente. Digo eu..

Obrigado pela atenção,

alves077

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

o meu é mais deste género

Meh. Devia de ter explicado melhor.

De qq modo, esta função só lê o array, por isso, é seguro para multiplas threads (AKA thread-safe) porque esta função pode ser executada por multiplas threads ao mesmo tempo.


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

volto a afirmar :

na minha perspectiva, a função só é thread-safe se garantir que a sua execução não se encontra em causa por execução de esta ou outra função num segundo thread.

a leitura de dados não é só por si thread-safe

novo caso exemplo:

- novamente um array com 3 elementos (1, 2, 3)

- uma função que soma soma aos elementos, o valor do elemento anterior

- uma função que imprime no ecrã os valores do array:

int * array = {1, 2, 3};

int output(int * array, size_t array_size)
{
 int i;
 for (i = 0; i < array_size, i++)
   printf("%d ", array[i]);
 printf("\n");
}

int inc(int * array, size_t array_size)
{
 int i;
 for (i = 1; i < array_size, i++)
   array[i] + array[i + 1];
}

execução exemplo que a leitura não é thread-safe:

                                 programa
                                    |
               <--------------------v
            thread 1
          criado (output)
               >-----------------------------------------v
                                                      thread 2
                                                    criado (inc)
               v-----------------------------------------<
            thread 1
        printf("%d ", 1);
               |
            thread 1
        printf("%d ", 2);
               >-----------------------------------------v
                                                      thread 2
                                           array[1] = array[0] + array[1]
                                                     (1, 4, 3)
                                                         |               
                                                      thread 2
                                           array[2] = array[1] + array[2]
                                                     (1, 4, 6)
               v-----------------------------------------<
            thread 1
        printf("%d ", 6);
               >--------------------v
                              resultado final
                              consola : 1 2 6
                                    !=
                  consola : 1 2 3 (output antes de inc)
                                    ou
                            1 4 6 (inc antes de output)


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

Só para eu ter noção, então, do que consideras thread-safe...

Então, para ti, só uma função que não recebe apontadores, não tem variáveis static e não usa variáveis globais (direta ou indiretamente) é thread-safe, certo? Senão, mostra um exemplo que não siga isto e consideras thread-safe.

Editado por brunoais

"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

só uma função que não recebe apontadores, não tem variáveis static e não usa variáveis globais (direta ou indiretamente) é thread-safe, certo?

não

uma função thread-safe é uma que, se manipula um dos tipos de dados descritos por ti, toma medidas para que a sua manipulação seja feita sem problemas de concorrência.

mostra um exemplo que não siga isto e consideras thread-safe.

#include <pthread.h>

struct TSArray
{
 pthread_mutex mutex;
 int * array;
 size_t array_size;
}

void f(struct TSArray * array)
{
 int i;

 pthread_mutex_lock(&array->mutex);
 for (i = 1; i < array->array_size; i++)
   array->array[i] += array->array[i - 1];  
 pthread_mutex_unlock(&array->mutex);
}

(é claro que não existe garantia que a manipulação seja correcta, mesmo com o mutex, caso exista outro tipo de manipulação dos dados que não seja thread-safe)


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
brunoais

Por isso... Aparentemente, a única maneira, para ti, de ter uma função thread-safe, em que usa variáveis do exterior (escrevo assim só para simplificar), é usando um lock, certo?

Agora ajuda-me a perceber aonde é que as regras do teu exemplo se enquadram nas regras do problema do autor deste tópico.

Há um promenor que não estás a tomar em conta no teu exemplo.

No caso do código do autor:

Todo o valor que é referenciado (diretamente ou indiretamente) por quaisquer paramentos inicializados, usados como input da função não são alterados.

No teu caso:

Um conteúdo que a variável 'array' aponta (direta ou indiretamente) é alterada para um valor diferente.

Por isso, o exemplo que usas para mostrar que não é thread-safe é inválido.


"[Os jovens da actual geração]não lêem porque não envolve um telecomando que dê para mirar e atirar, não falam porque a trapalhice é rainha e o calão é rei" autor: thoga31

Life is a genetically transmitted disease, induced by sex, with death rate of 100%.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.