【问题标题】:Why my double linked list insertion fail?为什么我的双链表插入失败?
【发布时间】:2013-04-04 06:07:59
【问题描述】:

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

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);
}

【问题讨论】:

  • 这两个定义没有区别,除非我遗漏了什么。 (nextprev 的顺序?)此外,“将失败”是对问题的一个非常糟糕的描述,无论它是什么。
  • @DavidSchwartz 请点击我的链接并查看我的代码。
  • @prehistoricpenguin 您在此处发布的两个定义没有区别。
  • 如果这些分别是有效/失败的定义,那么我的水晶球告诉我你的节点的前 4 个字节正在被覆盖(不知何故),从而阻止你在列表中前进,直到您将next 指针移动到我们的伤害方式(但仍然打赌prev 已被冲洗)。

标签: c linked-list


【解决方案1】:

此代码将指向 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 的值,尽管您绝对不应该这样做。 “碰巧”起作用的代码的问题在于,有时它碰巧不起作用。

【讨论】:

    【解决方案2】:

    查看您的代码,问题在于您将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 的含义。 (一种情况是内存中的第一个和第二个指针,另一种情况是内存中的第二个和第一个指针)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      相关资源
      最近更新 更多