Week 3 隨堂測驗 (下)
目的: 檢驗學員對 C 程式設計的認知
姓名 *
學號 (旁聽請填旁聽) *
測驗 1
以下程式碼是個 XOR linked list [1] 的實作,在這樣的資料結構可表示為:
             1       2       3       4
data  HAT  CAT  EAT  BAT
link       2       2       6       3
要往下一格移動時,我們需要前一格在哪和這一格的位置。例如我們現在在 HAT (1), 已知前一格是 (0),那麼下一格就是 link(1) XOR 0 = 2 XOR 0 = 2,也就是 CAT。繼續,現在位於 CAT (2),前一格在 (1),於是下一格就是 link(2) XOR 1 = 2 XOR 1 = 3,亦即 EAT,依此類推。只要當找出來的下一格是 (0) 就結束。
#include <stdio.h>                                                                                                                                            
#include <stdlib.h>

typedef struct {
    unsigned long lxr;
    int data1, data2;
} item;
item *lh = NULL;
       
typedef struct { item *left, *right; } lxr_info;
       
void print_at(lxr_info *p_lxri, item *pli) {  
    if (pli)
        printf("data1 = %d, data2 = %d\n", pli->data1, pli->data2);
}

static inline item *extract_address(item *lxr, item *other) {
    return (item *) (lxr->lxr ^ (unsigned long) other);
}  

static inline void shift_lxr(item *lxr, item *known, item *update) {
    lxr->lxr = (lxr->lxr ^ (unsigned long) known) ^ (unsigned long) update;
}

/* Walk the list starting at the header */
void list_walk(void) {
    item *pcur = lh;
    lxr_info lxri = {.left = NULL, .right = NULL};
    lxri.right = extract_address(pcur, lxri.left);
    while (pcur) {
        print_at(&lxri, pcur);
        pcur = lxr_move_right(&lxri, pcur);
    }
}

/* Append an item where we are */
item *append_item(lxr_info *p_lxri, item *p_current, int d1, int d2) {
    item *p_this, *p_left, *p_right;
    if ((p_this = calloc(1, sizeof(item)))) {
        p_left = p_lxri->left = p_current;
        p_right = p_lxri->right;
        UCCU;
        VCCV;
        p_this->lxr = (unsigned long) p_current ^ (unsigned long) p_lxri->right;
        p_this->data1 = d1;
        p_this->data2 = d2;
    }
    return p_this;
}

int main(int argc, char **argv) {
    int index = 0;
    int maxrun = 20;
    item *pcur = lh, *pnli;
    lxr_info lxri = {.left = NULL, .right = NULL};

    while (index < maxrun) {
        if ((pnli = append_item(&lxri, pcur, 3 * index, 3 * index + 1)) ==
            NULL) {
            exit(2);
        }
        pcur = pnli;
        if (!lh)
            lh = pcur;
        index++;
    }

    list_walk();
    return 0;
}
作答區
UCCU = ? *
25 points
VCCV = ? *
25 points
延伸問題
1. 設計實驗探討 XOR linked list 的記憶體開銷,相較於典型的設計,能省多少呢?
2. 在 Linux 核心原始程式碼找出特製的 linked list,並予以解說
測驗 2
考慮以下實作 Reference counting [1] 的程式碼:
#include <stddef.h>                                                                                                                                          
#include <stdio.h>
#include <stdlib.h>
       
struct ref {
    void (*free)(const struct ref *);
    int count;
};  
static inline void ref_inc(const struct ref *ref) {
    ((struct ref *) ref)->count++;
}  
   
static inline void ref_dec(const struct ref *ref) {
    if (--((struct ref *) ref)->count == 0)
        ref->free(ref);
}
   
#define container_of(ptr, type, member) \
    ((type *) ((char *) (ptr) -offsetof(type, member)))

struct node {
    char id[64];
    float value;
    struct node *next;
    struct ref refcount;
};      
   
static void node_free(const struct ref *ref) {
    struct node *node = container_of(ref, struct node, refcount);
    struct node *child = node->next;
    free(node);
    ABA;
}

struct node *node_create(char *id, float value) {
    struct node *node = malloc(sizeof(*node));
    snprintf(node->id, sizeof(node->id), "%s", id);
    node->value = value;
    node->next = NULL;
    node->refcount = (struct ref){node_free, 1};
    return node;
}

void node_push(struct node **nodes, char *id, float value) {
    struct node *node = node_create(id, value);
    node->next = *nodes;
    *nodes = node;
}

struct node *node_pop(struct node **nodes) {
    struct node *node = *nodes;
    *nodes = (*nodes)->next;
    if (*nodes)
        CDC;
    return node;
}
   
void node_dump(struct node *node) {
    for (; node; node = node->next)
        printf("%s = %f\n", node->id, node->value);
}
   
int main(void) {
    struct node *nodes = NULL;
    char id[64];
    float value;
    node_push(&nodes, "foo", 0.1f);
    node_dump(nodes);
    struct node *old = node_pop(&nodes);
    node_push(&nodes, "bar", 0.2f);
    node_dump(nodes);
    ref_dec(&old->refcount);
    ref_dec(&nodes->refcount);
    return 0;
}
作答區
ABA = ? *
25 points
CDC = ? *
25 points
延伸問題
1. 這個 reference counting 實作沒考慮到 thread safety (https://en.wikipedia.org/wiki/Thread_safety),請著手改善並設計驗證機制;
2. 在 Linux 核心找出類似的 reference counting 程式碼並解說;
Submit
Clear form
Never submit passwords through Google Forms.
This form was created inside of National Cheng Kung University. Report Abuse