为什么我的双链表插入失败?

时间:2013-04-04 06:08:00

标签: c linked-list

我正在编写一个带有双链表的简单计时器。如果我将链表头定义如下,它将起作用。

struct timer_head
{
    struct timer* prev;
    struct timer* next;
    pthread_spinlock_t lock;
};

但如果我将头部定义如下,那么插入将失败,我将在每次插入后丢失前一个节点。

struct timer_head
{
    struct timer* next;
    struct timer* prev;

    pthread_spinlock_t lock;
};

我的部分代码:

struct timer
{
    struct timer* prev;
    struct timer* next;
    struct timespec start;
    struct timespec interval;
    void* par, *par2; 
    /*if handle return 0    */
    /*then delete this timer    */
    /*else restart it       */
    int (*handler) (void* par);
};

struct timer_head
{
    struct timer* prev;
    struct timer* next;
/*
*if i changed the previous definition to 
*code below, then my list insertion will failed
*why?
*/
/*  struct timer* next;
    struct timer* prev;
*/
    pthread_spinlock_t lock;
};
void timer_queue_init(struct timer_head* lst)
{
    pthread_spin_init(&lst->lock, PTHREAD_PROCESS_SHARED);
    lst->next = lst->prev = (struct timer*)lst;
}

static void print_queue(struct timer_head* lst)
{
    pthread_spin_lock(&(lst->lock));
    struct timer* fst = lst->next;

    printf("list travserse:\t");
    while (fst != (struct timer*) lst)
    {
    printf("inteval : %ld, ", fst->interval.tv_nsec);
    fst = fst->next;
    }
    printf("\n");
    pthread_spin_unlock(&(lst->lock));
}


void timer_queue_insert(struct timer_head* lst, struct timer* nt)
{
    pthread_spin_lock(&(lst->lock));
    struct timer* ptr = lst->next;

    /*insert into list, sorted as earlist execute time  */
    while (ptr != (struct timer*) lst &&
        timespec_cmp(&(ptr->start), &(ptr->interval),
        &(nt->start), &(nt->interval)) <= 0)
    {
    printf("next\n");
    ptr = ptr->next;
    }
    nt->next = ptr;
    nt->prev = ptr->prev;

    nt->prev->next = nt;
    ptr->prev = nt;



    /* send signal to manage thread */
    if (!qlen)
    {
    printf("start :%ld s, %ld ns ", nt->start.tv_sec, nt->start.tv_nsec);
    printf("interval :%lds, %ld ns\n", nt->interval.tv_sec, nt->interval.tv_nsec);
    pthread_cond_signal(&wait);
    }
    ++qlen;
    pthread_spin_unlock(&(lst->lock));

    printf("traver after insert\t");
    print_queue(lst);
}

2 个答案:

答案 0 :(得分:2)

此代码将指向struct timer_head的指针转换为指向struct timer的指针。

void timer_queue_init(struct timer_head* lst)
{
   pthread_spin_init(&lst->lock, PTHREAD_PROCESS_SHARED);
   lst->next = lst->prev = (struct timer*)lst; /* HERE */
}

只要它们具有相同的结构,这就可以(运气好的)。您的struct timer看起来像这样:

struct timer
{
  struct timer* prev;
  struct timer* next;
  ...

因此,在prev之前放置next可以让演员“碰巧”保留prevnext的值,但绝对不应该这样做。代码“碰巧”工作的问题是,有时它会发生不起作用。

答案 1 :(得分:1)

查看您的代码,问题是您将timer_head *投射到timer *。如果timer_head看起来像

struct {
  struct timer * next;
  struct timer * prev;
  ...
}

然后在内存中你(可能)有以下布局

[next][prev]

。如果同时timer看起来像

struct {
  struct timer * prev;
  struct timer * next;
  ...
}

,就像你的代码一样,它在内存中有不同的布局,比如

[prev][next]

。从一个指针到另一个指针的演员表改变了prev和next的立场。 (在一种情况下,内存中的第一个和第二个指针,在另一种情况下是内存中的第二个和第一个指针)。