Que distribuição de probabilidade modela essa condição de corrida?

10

Considere o seguinte comando: bash -c "echo x; cat 1" | tee 1.

Meu entendimento é que ele seria bifurcado para um novo shell, xgravaria em stdout, file 1 not foundgravaria em stderr, sairia e retornaria o controle ao processo pai e xgravaria em stdout e em 1. Portanto, eu esperaria que a saída final fosse xe o arquivo 1contém exatamente a string x.

No entanto, este não é o caso. Na realidade, o arquivo 1geralmente contém pelo menos duas instâncias xe, às vezes, milhares de linhas de xs. Em um teste em lote de executar o comando dez mil vezes, o número médio de xs gravados no arquivo foi 52,3 e a mediana foi 1. Que mecânico está causando isso? Que distribuição de probabilidade modela esse comportamento? Suspeito que seja condicionalmente geométrico e uniforme.

Will Sherwood
fonte
3
Tem a ver com o momento da execução do lado esquerdo e direito do pipeline. Ambos são iniciados simultaneamente ou próximos a ele. Se você teeabriu o arquivo para gravação antes de abri- catlo para leitura, você pode obter muitos x-es no arquivo. Nesse caso, o "loop" terminaria sempre que a catleitura fosse mais rápida que a teegravação, atingindo o final do arquivo.
Kusalananda
De testes limitados aqui, o número médio de xs gravados no arquivo foi de 4,35. Eu acho que vai depender muito da carga da máquina.
Renan

Respostas:

1

Como é muito curioso, tentei investigá-lo com a ajuda do strace. Execute seu comando em um loop 1000 vezes:

mkdir {000..999}
for i in {000..999}; do
echo $i
(cd $i; strace -f -o trace.log bash -c 'bash -c "echo x; cat 1" | tee 1 >/dev/null'; )
done

Encontrei o arquivo com mais linhas ( wc -l */1 | sort -nr | head -n2) e verifiquei o correspondente trace.log. Certamente posso ver muitos:

7567  <... read resumed> "x\n", 8192)   = 2
7567  write(1, "x\n", 2)                = 2
7567  write(3, "x\n", 2)                = 2
7567  read(0,  <unfinished ...>
7568  read(3, "x\n", 131072)            = 2
7568  write(1, "x\n", 2)                = 2
7567  <... read resumed> "x\n", 8192)   = 2
7567  write(1, "x\n", 2)                = 2
7567  write(3, "x\n", 2)                = 2
7567  read(0,  <unfinished ...>
7568  read(3, "x\n", 131072)            = 2
7568  write(1, "x\n", 2)                = 2
7567  <... read resumed> "x\n", 8192)   = 2
7567  write(1, "x\n", 2)                = 2
7567  write(3, "x\n", 2)                = 2
7567  read(0,  <unfinished ...>

Onde 7567 é tee 1e 7568 é cat 1. Os dois definitivamente estão alternando, então sim, como se suspeita, isso é tudo sobre o momento da execução (e eu imagino a alternância de contexto) dos dois comandos.

chutz
fonte