Linus Torvalds (torvalds@cs.helsinki.fi)
Ter, 6 de agosto de 1996 12:47:31 +0300 (EET DST)
Mensagens ordenadas por: [data] [tópico] [assunto] [autor]
Próxima mensagem: Bernd P. Ziller: "Re: Ops em get_hash_table"
Mensagem anterior: Linus Torvalds: "Re: pedido de solicitação de E / S"
Em segunda-feira, 5 de agosto de 1996, Peter P. Eiserloh escreveu:
Precisamos manter um conceito claro de threads. Muitas pessoas parecem confundir um segmento com um processo. A discussão a seguir não reflete o estado atual do linux, mas é uma tentativa de permanecer em uma discussão de alto nível.
NÃO!
Não há razão para pensar que "threads" e "processos" são entidades separadas. É assim que é feito tradicionalmente, mas eu pessoalmente acho que é um grande erro pensar dessa maneira. A única razão para pensar dessa maneira é a bagagem histórica.
Tanto os threads quanto os processos são realmente apenas uma coisa: um "contexto de execução". Tentar distinguir artificialmente diferentes casos é apenas autolimitado.
Um "contexto de execução", chamado COE, é apenas o conglomerado de todo o estado desse COE. Esse estado inclui coisas como estado da CPU (registros, etc.), estado da MMU (mapeamentos de páginas), estado de permissão (uid, gid) e vários "estados de comunicação" (arquivos abertos, manipuladores de sinais etc.). Tradicionalmente, a diferença entre um "encadeamento" e um "processo" é principalmente o fato de um encadeamento ter o estado da CPU (+ possivelmente algum outro estado mínimo), enquanto todo o outro contexto vem do processo. No entanto, essa é apenas
uma maneira de dividir o estado total do COE, e não há nada que diga que é a maneira certa de fazê-lo. Limitar-se a esse tipo de imagem é simplesmente estúpido.
A forma como o Linux pensa sobre isso (e do jeito que eu quero que as coisas trabalho) é que não é nenhuma coisa como um "processo" ou um "thread". Existe apenas a totalidade do COE (chamado "tarefa" pelo Linux). Diferentes COEs podem compartilhar partes de seu contexto entre si, e um subconjunto desse compartilhamento é a configuração tradicional "thread" / "processo", mas isso realmente deve ser visto como APENAS um subconjunto (é um subconjunto importante, mas essa importância vem não do design, mas dos padrões: obviamente, também queremos executar programas de threads em conformidade com os padrões sobre o Linux).
Resumindo: NÃO projete de acordo com o modo de pensar do thread / processo. O kernel deve ser projetado com base na maneira de pensar do COE, e a biblioteca pthreads pode exportar a interface limitada do pthreads para usuários que desejam usar essa maneira de ver os COE.
Apenas como um exemplo do que se torna possível quando você pensa em COE em vez de encadear / processo:
- Você pode executar um programa externo "cd", algo que é tradicionalmente impossível no UNIX e / ou processo / thread (exemplo bobo, mas a idéia é que você pode ter esses tipos de "módulos" que não se limitam ao UNIX tradicional / instalação de threads). Faça um:
clone (CLONE_VM | CLONE_FS);
filho: execve ("cd externo");
/ * o "execve ()" desassociará a VM, portanto, o único motivo pelo qual usamos CLONE_VM foi tornar o ato de clonagem mais rápido * /
- Você pode executar o "vfork ()" naturalmente (ele atende ao suporte mínimo do kernel, mas esse suporte se encaixa perfeitamente na maneira de pensar da CUA):
clone (CLONE_VM);
filho: continue executando, eventualmente execve ()
mãe: aguarde execve
- você pode fazer "deamons de E / S" externos:
clone (CLONE_FILES);
filho: descritores de arquivo aberto etc
mãe: use os fd's que a criança abriu e vv.
Todas as opções acima funcionam porque você não está vinculado à maneira de pensar em threads / processos. Pense em um servidor da web, por exemplo, onde os scripts CGI são executados como "threads de execução". Você não pode fazer isso com os threads tradicionais, porque os threads tradicionais sempre precisam compartilhar todo o espaço de endereço; portanto, é necessário vincular tudo o que você sempre quis fazer no próprio servidor da Web (um "thread" não pode ser executado outro executável).
Pensando nisso como um problema de "contexto de execução", suas tarefas agora podem optar por executar programas externos (= separar o espaço de endereço do pai) etc, se quiserem, ou podem, por exemplo, compartilhar tudo com o pai, exceto por os descritores de arquivo (para que os sub- "threads" possam abrir muitos arquivos sem que o pai precise se preocupar com eles: eles fecham automaticamente quando o sub- "thread" sai e não usa fd no pai) .
Pense em um "inetd" encadeado, por exemplo. Você quer um overhead fork + exec baixo, portanto, com a maneira Linux, em vez de usar um "fork ()", você escreve um inetd multithread em que cada thread é criado apenas com CLONE_VM (compartilhe o espaço de endereço, mas não compartilhe o arquivo descritores etc). Em seguida, a criança pode executar se foi um serviço externo (rlogind, por exemplo), ou talvez tenha sido um dos serviços inetd internos (eco, horário do dia); nesse caso, apenas faz as coisas e sai.
Você não pode fazer isso com "thread" / "process".
Linus