Processos Threads vs (bifurcados)

9

Os aplicativos Linux geralmente bifurcam em seguida o exec (com execve ()), mas os aplicativos Java e certos MPMs do Apache usam threading. Se for bifurcação, usa o fork + exec para gerar um processo, qual é a versão de alto nível para a segmentação? Como a JVM ou o Worker MPM geram threads?

Gregg Leventhal
fonte
2
Confira Stackoverflow. Existem várias perguntas e respostas que explicaram parte disso.
Henk Langeveld

Respostas:

13

A idéia por trás de threads e processos é a mesma: você bifurca o caminho da execução. Caso contrário, os threads e processos diferem em coisas como memória. Ou seja, os processos têm espaço de VM diferente, enquanto os threads compartilham o que existia antes da divisão.

Subjacente ao trabalho de rosqueamento e forquilha usando a chamada clone () (man 2 clone):

Diferentemente do fork (2), o clone () permite que o processo filho compartilhe partes de seu contexto de execução com o processo de chamada, como espaço de memória, tabela de descritores de arquivo e tabela de manipuladores de sinal. (Observe que nesta página do manual, "processo de chamada" normalmente corresponde a "processo pai". Mas veja a descrição de CLONE_PARENT abaixo.)

O principal uso do clone () é implementar threads: vários threads de controle em um programa que é executado simultaneamente em um espaço de memória compartilhado.

As diferenças vêm dos sinalizadores que são passados ​​para o clone (). Como você pode ver na página de manual, fork e threading são apenas um conjunto de parâmetros predefinidos para clonar (). No entanto, também é possível fazer coisas personalizadas com ele.

V13
fonte
1
Uhm? O que? Releia quase todos os livros sobre o assunto, porque o espaço de memória separado para os processos é um grande problema. Também ajuda a "capturar" o código que trava, enquanto o kernel simplesmente mata um processo em que um thread individual fica descontrolado.
0xC0000022L 5/05
3
@ 0xC0000022L seu argumento não contradiz a resposta, como me parece.
Ruslan
1
@Ruslan: Eu imploro para diferir: "A idéia [...] é a mesma coisa"? A idéia por trás dos threads é de fato simultânea, mas para processos essa é uma história totalmente diferente.
0xC0000022L 5/05
4
@ 0xC0000022L Você perdeu a parte importante da resposta de V13: "Você bifurcar o caminho de execução" - a questão é sobre como tópicos são gerados, não o que a diferença entre segmentos e processos são
Izkata
@ Izkata: de modo algum. Eu apenas sustento que esta não é uma afirmação correta.
0xC0000022L 5/05
8

A maioria dos sistemas operacionais (SOs) de multiprocessamento não Unix usa uma chamada "spawn ()" ou algo semelhante para gerar um novo processo ou fluxo de controle do SO. Spawn () tende a ser uma chamada muito complexa, com muitas opções e muita sobrecarga. Uma das inovações do Unix foi fornecer uma maneira aérea muito mais baixa de criar processos - fork (). O Unix cuidou das muitas opções necessárias para gerar () permitindo quantidades arbitrárias de processamento antes da outra metade de spawn (), com exec ().

Como o Unix e suas variantes foram sendo usados ​​cada vez mais, a criação de processos de baixo custo adicional foi considerada útil e foi usada. De fato, era tão usado que as pessoas queriam maneiras mais baixas de criar processos, e assim nasceu a idéia de "threads". Originalmente, os threads foram manipulados completamente pelo processo de origem (e programas como a JVM podem fazer isso com "threads verdes"); mas o manuseio da programação multithread é complicado e frequentemente foi feito incorretamente. Portanto, há uma maneira mais fácil e intermediária de executar threads, em que o sistema operacional lida com o agendamento, mas algumas despesas gerais são salvas ao compartilhar (normalmente) o espaço de endereço entre os threads.

É difícil responder à sua pergunta porque existem vários conceitos diferentes, mas relacionados, que são todos "threads" e, para detalhes, você precisa de um adjetivo para descrever qual deles você está fazendo referência. Por outro lado, entender as diferenças provavelmente o levará à resposta específica desejada. Procure coisas como "processos leves", "threads de usuário" e "rfork ()" para obter mais informações.

mpez0
fonte
1
"manipular o agendamento de vários threads é complicado e frequentemente foi feito incorretamente", citação necessária. Implementar threads de espaço do usuário não é um problema. O problema com os encadeamentos do espaço do usuário é que, se um encadeamento executa uma chamada de sistema de bloqueio, todos os encadeamentos são bloqueados. A única maneira de evitar isso é usando threads no nível do sistema.
Bakuriu 5/05
1
Curiosamente, o Windows não incluiu essa inovação do Unix: ela possui, CreateProcess()mas nada parecido fork().
Ruslan
2
@Bakuriu - procure qualquer um dos muitos artigos sobre a criação de agendadores de multiprocessamento, mantendo a justiça, evitando a fome, lidando com prioridades etc. A implementação de threads no espaço do usuário não é, como você diz um problema. Agendar exemplos não triviais é difícil.
precisa saber é
@Ruslan: pode-se bifurcar no Windows, simplesmente não faz parte da API do Win32. Leia "A API nativa do Windows NT / 2000", de Nebbett. Ele tem uma implementação que imita fork().
0xC0000022L 5/05
3

Threads e bifurcação são, na verdade, dois conceitos diferentes, ambos existentes nos sistemas Unix / Linux (e ambos podem ser usados ​​no C / C ++).

A idéia de um fork () é (basicamente) a criação de um processo separado que possui o mesmo código de execução que o processo pai e que inicia a execução na linha de fork. O objetivo do uso de garfos com funções exec é que as funções exec fechem o processo que as chamou quando elas terminam. Portanto, você geralmente bifurca-se, obtendo o PID de cada processo (o filho sempre é 0) e faz com que o pai espere até que o filho termine de executar a função exec.

Os threads são usados ​​para paralelismo (lembre-se de que o pai espera o filho, geralmente, em um programa bifurcado). Um thread, como pthread em C / C ++ (faça uma pesquisa no Google), será executado paralelamente ao processo principal e pode compartilhar variáveis ​​globais e funções globais com o programa original. Como os threads Java se comportam de maneira semelhante, eu imaginaria que eles agem mais como esses threads do que como um processo de bifurcação.

Basicamente, há uma diferença entre bifurcação e rosqueamento. Eles fazem coisas distintamente diferentes (embora pareçam semelhantes). Esses conceitos podem ser difíceis de entender, mas você pode aprendê-los por meio de pesquisas (extensas) se tiver um desejo sincero de entendê-los.

EDIT # 1

Veja estes exemplos de como garfos e threads podem ser chamados e usados. Observe o comportamento das funções exec e seus efeitos no programa principal.

http://www.jdembrun.com:4352/computerScience/forkVSthread.zip

jaredad7
fonte
2
Fork (com ou sem exec) também pode ser usado para paralelismo. Não sei ao certo o que você quer dizer com "funções exec fecham o processo que as chamou quando elas terminam", exec faz muito tempo que termina quando o processo termina. Também pthreadé uma API, não uma implementação de encadeamento.
Mat
No caso do garfo, estou citando meu professor de SO. De acordo com o que ele nos disse, sim, o bifurcação poderia ser usado para executar em paralelo, mas, se usasse uma função exec, essa seria a última. Quanto ao pthread, foi concebido como exemplo.
Jaredad7 5/05
Exec seria a última chamada no código do chamador, não a última instrução do processo bifurcado. O processo bifurcado continuaria executando o código exec'd.
Mat
Seus comentários me levaram a testar essas coisas. Eu escrevi alguns programas em c ++ que demonstram o comportamento das funções exec e seus efeitos nos programas quando usados ​​em forks x threads. Por favor, veja a edição acima.
precisa saber é o seguinte
Receio que a maioria das pessoas não se preocupe em baixar isso. Seus exemplos também não ilustram as diferenças interessantes entre os modelos, principalmente relacionadas ao compartilhamento (ou não) do espaço de endereço.
Mat
1

Tanto a JVM quanto o Apache MPM dependem do kernel para encadeamentos nativos. Ou seja, eles usam o sistema operacional para agendá-los. É claro que ambos precisam de sua própria API para acompanhar as coisas.

O Stackoverflow já possui várias perguntas sobre isso:

  1. JVM threads nativos , confira esta resposta para obter mais detalhes.

  2. O Apache possui dois tipos de MPMs: Prefork, com um processo por encadeamento, e Worker, que lida com vários encadeamentos: MPMs Apache . Confira a referência acodebucket

Henk Langeveld
fonte
1

Se for bifurcação, usa o fork + exec para gerar um processo, qual é a versão de alto nível para a segmentação? Como a JVM ou o Worker MPM geram threads?

Isso é específico da plataforma, mas no Linux e eu presumiria que muitos outros sistemas compatíveis com POSIX usam a implementação local de pthreads , uma API de segmentação de usuário. Por exemplo:

#include <pthread.h>

pthread_t tid;
pthread_create(&tid, NULL, somefunc, NULL);

Inicia uma nova chamada de thread somefunccomo seu primeiro ponto de execução.

Você também pode criar threads - distintos dos garfos, pois compartilham o mesmo espaço de memória heap global do processo pai, em vez de obter uma cópia duplicada (mas observe que os threads são executados com uma memória de pilha independente ) - com a clone()chamada do sistema, que é o que pthreads é construído sobre.

Cachinhos Dourados
fonte