Rodrigo Strauss :: Blog
Desafios aos Caçadores de Bugs
Enquanto escrevia a parte 2 sobre sincronização, encontrei um bug na utilização das funções Win32 na parte 1. Qual é o bug?
Em 13/09/2008 06:08, por Rodrigo Strauss
|
||||
| Contato Sobre... | ||||
|
||||
|
|
Rodrigo Strauss :: BlogDesafios aos Caçadores de BugsEnquanto escrevia a parte 2 sobre sincronização, encontrei um bug na utilização das funções Win32 na parte 1. Qual é o bug? Em 13/09/2008 06:08, por Rodrigo Strauss |
|||
|
|
||||
|
||||
|
||||
Comentários
Rodrigo Strauss | website | em 16/09/2008 | #
Não é isso, é um bug mesmo, que faz com que o resultado seja bem diferente do esperado.
Eduardo | em 17/09/2008 | #
O problema esta no WaitForMultipleObjects. Examinando a documentação o número máximo de handles é definido por MAXIMUM_WAIT_OBJECTS (buscando qual é o valor encontrei 67) e como se esta criando 100, um valor maior do que o suportado, ocorre um erro 87 e conseqüentemente o programa não funciona como deveria.
Fernando Roberto | website | em 17/09/2008 | #
//-f--> Os comentários que começarem com esse "f" // é um cacuete meu e servirá para fazer os // comentários a respeito do bug que espero // ter encontrado. void AddAfter(NODE* node, T data) { //-f--> Pelo nome deste método, estou admitindo que // posso utilizá-lo para inserir um nó após qualquer // outro nó existente, e não somente após o rootNode_ // como é utilizado neste exemplo. // // AddAfter(&rootNode_, data); //-f--> Na linha seguinte é alocado o registro que deverá // ganhar um lugar na lista ligada (lembre-se dele) NODE* newNode = new NODE(); // // primeiro item? // //-f--> Seguindo meu comentário anterior, para detectar se // o elemento que estou inserindo agora é o primeiro, // eu deveria fazer o teste da linha seguinte utilizando // a variável rootNode_ e não utilizando o parâmetro // node, que neste exemplo é sempre o rootNode_. // Se um parâmetro tivesse sempre que ter o mesmo valor, // então não deveria ser um parâmetro. //if(node->next == NULL) if (node == &rootNode_ && node->next == NULL) { //-f--> Desta forma, teriamos que mudar este ASSERT também //ASSERT(node->previous == NULL && node == &rootNode_); ASSERT(node->previous == NULL); //-f--> Aqui deveriamos colocar o novo nó na lista que foi // alocado no inicio deste método (lembra dele?) e não // o próprio nó passado como parâmetro //node->next = node->previous = node; node->next = node->previous = newNode; //-f--> Aqui imagino que deveriamos vincular o dado que // veio como parâmetro ao novo nó alocado. //node->data = data; newNode->data = data; return; } else { // // refaz todos os links, para que o nó inserido // fique entre o nó passado como parâmetro // e o próximo // //-f--> Aqui parece que está tudo certo newNode->next = node->next; node->next = newNode; newNode->previous = node; newNode->next->previous = newNode; newNode->data = data; } //-f--> Uma última observação aqui seria referente ao uso // de rootNode_.data. // Pelo que foi visto neste método, o rootNode_.data // nunca terá um dado associado a ele, pois as // associações são sempre feitas como mostra abaixo: // // newNode->data = data; // // Vou desconsiderar que teremos um espaço do tipo T // que nunca será utilizado, afinal isso é apenas // um exemplo. // Mas o método Dump mostra o rootNode_.data e o // método Count o conta como um registro válido. // Assim temos uma ambiguidade aqui. Não sei se o // erro está em não utilizar o rootNode_.data ou // se o erro está em levá-los em consideração nos // métodos Dump e Count. count_++; } //-f--> Não sou de ficar caçando bugs nos posts dos outros, // mas o convite foi tentador. Espero ter acertado :-) // // PS: Sou irmão do Kabloc ;-)
Wander | em 19/09/2008 | #
No caso em que if(node->next == NULL) For verdadeiro, temos um memory leak? Além disso, count_ não é atualizado também... PS: acabei colocando minha resposta no post errado. | ||||
|
||||
| :::: | ||||
Apesar de ser um erro mais conceitual do que de programação em si, a chamada a CreateThread no bloco:
for(DWORD a = 0 ; a < threadCount ; a++)
threads.push_back(CreateThread(NULL, NULL, &WorkerThread, &info, NULL, &dwThreadID));
Não está muito correta, apesar de NULL geralmente ser um define para 0, o segundo e o penúltimo parâmetros da função não são ponteiros, e sim o tamanho da stack da nova thread (0 quer dizer o tamanho padrão do processo) e flags de criação (0 quer dizer que a thread começa a rodar assim que é criada), respectivamente. Mesmo sendo os valores literais 0 e 0, os parâmetros mais comuns à chamadas de CreateThread, o conceito de que NULL é um ponteiro faz a chamada realizada no código estar "errada".
Se o erro não for esse, acredito que seja conceitual, porque o programa funciona (para seu propósito de "não funcionar"), não?!
Como cheguei aqui? Kbloc Vacavoa compartilhou este post no Google Reader ;]