2012-02-09 4 views
11

Estoy aprendiendo a usar la API de lista de enlaces del kernel desde list.h.¿Por qué necesitamos list_for_each_safe() para eliminar nodos en la lista de kernel linked?

Me enteré de que necesito usar list_for_each_safe() al eliminar nodos con list_del() en lugar de usar list_for_each().

Código de list_for_each_safe():

#define list_for_each_safe(pos, n, head) \ 
    for (pos = (head)->next, n = pos->next; pos != (head); \ 
     pos = n, n = pos->next) 

Código de list_for_each():

for (pos = (head)->next; pos != (head); pos = pos->next) 

Me he dado cuenta que ambos son muy similares excepto que la versión _safe toma un argumento adicional para ser utilizado como 'almacenamiento temporal' (indicado aquí, list.h).

Entiendo cuándo aplicar la función correctamente, _safe versión para eliminar, versión normal para acceder, pero me llama la atención cómo el argumento adicional lo hizo 'seguro'?

considere lo siguiente, donde estoy borrando cada nodo en una lista enlazada utilizando list_for_each_safe():

struct kool_list{ 
    int to; 
    struct list_head list; 
    int from; 
    }; 

struct kool_list *tmp; 
struct list_head *pos, *q; 
struct kool_list mylist; 

list_for_each_safe(pos, q, &mylist.list){ 
     tmp= list_entry(pos, struct kool_list, list); 
     printf("freeing item to= %d from= %d\n", tmp->to, tmp->from); 
     list_del(pos); 
     free(tmp); 
    } 

¿Cómo dar q ayuda en la eliminación de?

¡Gracias por cualquier ayuda!

+0

lo tengo, nunca pensó que esto es lo sencillo, Gracias ! –

+0

q debería haber sido nombrado de una mejor manera ... algo así como pos_next. –

Respuesta

20

Eso es necesario porque list_del internamente modifica el valor de pos campos. En su ejemplo, el cuerpo del bucle incluso libera la memoria ocupada por pos. Supongamos que utilizaría la versión insegura del bucle:

for (pos = (head)->next; pos != (head); pos = pos->next) 

Después de ejecutar el cuerpo del bucle pos puntero se convierte en inválida romper la expresión de la subasta: pos = pos->next.

Como opuesto, el foreach segura pre-guarda el valor de pos->next en una variable temporal y luego se refiere a este último en lugar de eliminación de referencias pos:

for (pos = (head)->next, n = pos->next; pos != (head); \ 
    pos = n, n = pos->next) 
2
pos = start; 
del(pos); 
pos = pos->next; 

en contraposición a

pos = start; 
n = pos->next; 
del(pos); 
pos = n; 

si del() es libre() y memset(), po-> siguiente es indefinido

Cuestiones relacionadas