Por que minhas variáveis ​​não estão segurando o estado após o WaitForSingleObject?

StackOverflow https://stackoverflow.com/questions/4017131

Pergunta

Estou implementando um protocolo DO VOLTO N para uma classe de rede. Estou usando o waitforsingleObject para saber quando o soquete do meu thread receptor tem dados dentro dele:

int result = WaitForSingleObject(dataReady, INFINITE);

Para voltar n, tenho que enviar vários pacotes para o receptor de uma só vez e manipular os dados e enviar um pacote ACK de volta ao remetente. Eu tenho uma variável esperada que eu incremento cada vez que envio um ACK para saber se um pacote chegar fora de ordem.

No entanto, quando o primeiro pacote chega, meu depurador me diz que o esperadoseq foi incrementado, mas quando o próximo pacote está sendo manipulado, o esperado que oseq ainda é seu valor original.

Alguém tem alguma ideia de por que isso está ocorrendo? Se eu colocar uma declaração IF como tal

if(recvHeader->seq == expectedSeq+1)

O segundo pacote se registra corretamente e envia um ACK. Claramente, isso não funcionará para nenhuma quantidade de pacotes superiores a 2 tho.

Eu tentei encerrar a seção inteira (incluindo o WaitForSingleObject original) em um semáforo, na tentativa de fazer tudo esperar até depois que a variável foi incrementada, mas isso também não funcionou.

Obrigado pela ajuda!

Eric

Por solicitação: mais código!

WaitForSingleObject(semaphore, INFINITE);
int result = WaitForSingleObject(dataReady, timeout);
if(result == WAIT_TIMEOUT)
   rp->m->printf("Receiver:\tThe packet was lost on the network.\n");
else {
  int bytes = recvfrom(sock, recv_buf, MAX_PKT_SIZE, 0, 0, 0);
  if(bytes > 0) {
   rp->m->printf("Receiver:\tPacket Received\n");
   if(recvHeader->syn == 1 && recvHeader->win > 0)
       windowSize = recvHeader->win;

   //FORMER BUG: (recvHeader->syn == 1 ? expectedSeq = recvHeader->seq : expectedSeq = 0);
   if(recvHeader->syn)
      expectedSeq = recvHeader->seq;
   switch(rp->protocol) {
      case RDT3:
         ...
      break;
      case GBN:
         if(recvHeader->seq == expectedSeq) {
            GBNlastACK = expectedACK;
            //Setup sendHeader for the protocol
            sendHeader->ack = recvHeader->seq;
            ...
            sendto(sock, send_buf, sizeof(send_buf), 0, (struct sockaddr*) &send_addr, sizeof(struct sockaddr_in));
            if(sendHeader->syn == 0) { //make sure its not the first SYN connection packet
               WaitForSingleObject(mutex, INFINITE);
               expectedSeq++;
               ReleaseMutex(mutex);
               if(recvHeader->fin) {
                  fin = true;
                  rp->m->printf("Receiver:\tFin packet has been received. SendingOK\n");
               }          
            }
         }
    break;
    }//end switch
}
Foi útil?

Solução 2

Enquanto entrava no meu código (digitando a mão, pois meu código estava em outro computador), percebi um bug muito estúpido quando estava definindo o valor original para o esperado. Eu estava configurando para 0 a cada execução de um pacote.

Tem que amar o código que sai quando você está codificando até as 5 da manhã!

Outras dicas

Exatamente como e quando você aumenta expectedSeq? Pode haver um problema de barreira de memória envolvido, então você pode precisar acessar expectedSeq Dentro de uma seção crítica (ou protegido por algum outro objeto de sincronização) ou uso Interlocked APIs para acessar a variável.

Por exemplo, o compilador pode estar em cache o valor de expectedSeq Em um registro, as APIs de sincronização podem ser necessárias para impedir que isso aconteça em áreas críticas do código. Observe que usando o volatile A palavra -chave pode parecer ajudar, mas provavelmente também não é totalmente suficiente (embora possa com o MSVC, já que o compilador da Microsoft usa barreiras completas de memória ao lidar com volatile objetos).

Eu acho que você precisará postar mais código mostrado exatamente como você está lidando expectedSeq.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top