安裝R語言

文章目錄
  1. Purpose
  2. 安裝
    1. 添加新的套件source 到sources.list
    2. 更新AP
    3. 安裝 R

Purpose

最近股市賠錢,覺得應該是要改變自己對投資的態度,要更積極一點

而且需要明白如何透過一些分析的軟體來作投資策略分析.

在網路上尋找到一個數據分析的軟體, 稱作"R語言"

R語言,一種自由軟體程式語言與操作環境,主要用於統計分析、繪圖、資料探勘。R本來是由來自紐西蘭奧克蘭大學的Ross Ihaka和Robert Gentleman開發(也因此稱為R),現在由「R開發核心團隊」負責開發。R是基於S語言的一個GNU計劃專案,所以也可以當作S語言的一種實作,通常用S語言編寫的代碼都可以不作修改的在R環境下執行。R的語法是來自Scheme。

安裝

添加新的套件source 到sources.list

1
2
sudo vim /etc/apt/sources.list
deb http://<my.favorite.cran.mirror>/bin/linux/ubuntu trusty/

改成適當的mirror 聯結

假如在臺灣的話,參考底下

Taiwan

http://ftp.yzu.edu.tw/CRAN/ Department of Computer Science and Engineering, Yuan Ze University http://cran.csie.ntu.edu.tw/ National Taiwan University, Taipei

更新AP

輸入底下command

1
sudo apt-get update

假如你遇到底下問題,無法正常update的話

1
W: GPG 錯誤: http://cran.csie.ntu.edu.tw trusty/ Release: 由於無法取得它們的公鑰,以下簽章無法進行驗證: NO_PUBKEY 51716619E084DAB9

將51716619E084DAB9改成你在terminal看到的key, 並輸入底下cmd.

1
2
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys FAF69C646FF368B7
sudo apt-get update

安裝 R

1
sudo apt-get install r-base

[VIM]How to Copy&Paste in different VIM terminal

文章目錄
  1. PURPOSE
  2. How TO Do
    1. Check your VIM information first
    2. Install the VIM-Plugin to enable the feature.

PURPOSE

Recent I want to copy&past in different VIM terminals, so I spent a few time to figure out how to do that. w

How TO Do

There is a simple way to do.

Check your VIM information first

  1. open the shell terminal
  2. type the following command to check the vim information
1
vim --version | grep xterm_clipboard

If you find the below message, it tells you that the xterm_clo[board of VIM is off

1
-xterm_clipboard

Install the VIM-Plugin to enable the feature.

1
2
3
sudo apt-get install vim-athena
sudo apt-get install vim-gnome
sudo apt-get install vim-gtk

[AtoI/ItoA] Sample Code

文章目錄
  1. Purpose
  2. My ATOi
  3. My IToA
  4. Testing

Purpose

每天寫一點小程式,雖然簡單,但是也讓我心情開心,慢慢的讓程式實作能力,變得更有自信.

昨天寫了基本常用的 atoi和itoa 的基本 c api.也算是面試常見用的考古題.

順便複習一下,也是好事情.

My ATOi

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Ret my_atoi(int* num, const char* char_num) 
{
// 檢查 poineter 是否爲空的, 是的話, return fail
check_pointer_return_value(char_num, Ret_Fail);

// init the total value
int total = 0;

// 檢查是否爲負數
int is_positive = 1;
if (char_num[0] == '-')
{
//若爲負數的話,就記錄下來
is_positive = -1;
char_num ++;
}

// 將每個字元,減去'0',這樣就可以得到字元的value,
// 舉例: '0' = 30, '9' = 39 , 若是我要得到字元9的值, 就用 '9'-'0'=39-30=9
while ( *char_num != '\0')
{
// 將10進位的數往左推一個
total *= 10;
total += *char_num - '0';
char_num++;
}

*num = total*is_positive;

return Ret_Success;
}

My IToA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
Ret my_itoa(int num, char* char_num)
{
check_pointer_return_value(char_num, Ret_Fail);

int is_negative = 0;
char* return_char = char_num;

// 處理負數
if (num < 0)
{
is_negative = 1;
num *= -1;

}

// 處理0
if (num == 0)
{
*char_num = '0';
return Ret_Success;
}

while ( num != 0)
{
// 將0~9的值轉成字元,其實很間單,就是加上'0' 或是 30
*char_num = '0' + (num % 10);
num /= 10;
char_num++;
}

if (is_negative)
{
// 若爲負數的話,將'-'加入字串中
*char_num = '-';
char_num++;
}

// Revert string
Revert(return_char);

return Ret_Success;

}

Ret Revert(char* num_char)
{
check_pointer_return_value(num_char, Ret_Fail);

int length = strlen(num_char);

int i;
// 將字串中的字元整份顛倒
for (i=0; i<length/2; i++)
{
char temp_char ;
temp_char = num_char[i] ;
// swap
num_char[i] = num_char[length-1-i];
num_char[length-1-i] = temp_char;
}

return Ret_Success;
}

Testing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>
#include <string.h>

typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None
}Ret;

Ret my_atoi(int* num, const char*);
Ret my_itoa(int num, char* char_num);

#define check_pointer_return_value(ptr,value) if(ptr==NULL) \
{ printf(" pointer is NULL !!!"); \
return value; } \

void main(void)
{
char test_char[] = "-159";
char test_char2[] = "269";
int temp_num ;
my_atoi(&temp_num,test_char);
printf("my_atoi : strlen(test_char) = %zu, test = %d \r\n", strlen(test_char),temp_num );
my_atoi(&temp_num,test_char2);
printf("my_atoi : strlen(test_char2) = %zu, test2 = %d \r\n", strlen(test_char2), temp_num);

char test_char3[255] = "";
my_itoa(128, test_char3);
printf("my_itoa : %s \r\n", test_char3);
memset(test_char3,'\0',strlen(test_char3));
my_itoa(-259, test_char3);
printf("my_itoa : %s \r\n", test_char3);

}

[Stack] Create the Stack Structure by Double Link List

文章目錄
  1. Purpose
  2. Concept
  3. FULLL CODE

Purpose

繼前前篇的實作queue結構,最後再補上如何透過組合double link list的方式,

實作stack strcutre的操作API. 實在是容易,其實就是雙向鏈接的特殊形式.

Concept

Stack 就是Fist In Last Out, 也就是我們熟知的先進後出,或稱作後進先出.

把握這個概念. 所以在Stack.h 下,我開出了底下對外的API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Stack.h

#include "DList.h"

typedef struct _Stack
{
DList* HeadNode;
}Stack;

Stack* Stack_Create(void);
Ret Stack_Destroy(Stack*);
Ret Stack_Print_all(Stack*, DList_Print);
Ret Stack_Push(Stack*, DList* InsertNode);
Ret Stack_Pop(Stack*);
Ret Stack_Get_Length(Stack*, int* length);
Ret Stack_Get_Node(Stack*, DList**);

看吧, 自定的stack structure,其實就是指向雙向鏈結頭的指標.

Stack_Pop就是將一個雙向鏈結的Node(index=1) 移除. (我定義的雙向鏈結,Head Node,不能當作是data node).

所以總是清除掉最後進來的Node.

而Stack_Push,也是一樣,插入一個Node,到index=1的地方.

所以總是將Node 放到最靠近Head Node的地方.

多了一個 Stack_Get_Node, 這其實是將 index=1的Node 取出來,但是我並沒有清除掉index=1的Node.

所以大致就是這樣囉...

FULLL CODE

1. stack.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdlib.h>
#include "stack.h"

Stack* Stack_Create(void)
{
Stack* myStack = (Stack*)malloc(sizeof(Stack));
check_pointer_return_value(myStack, NULL);

myStack->HeadNode = DList_Create();
return myStack;
}

Ret Stack_Destroy(Stack* myStack)
{
check_pointer_return_value(myStack, Ret_Fail);
if ( Ret_Fail == DList_Destroy( myStack->HeadNode) )
{
SR_ERR("DList_Destroy FAILLL\n");
return Ret_Fail;
}
SR_DBG("Free the QUEUE\n");
free(myStack);
return Ret_Success;
}

Ret Stack_Print_all(Stack* myStack, DList_Print Print)
{
check_pointer_return_value(myStack, Ret_Fail);
return DList_Print_all(myStack->HeadNode, Print);
}

Ret Stack_Push(Stack* myStack, DList* InsertNode)
{
// I think the Head Node doesn't belong to be the Data Node.
check_pointer_return_value(myStack, Ret_Fail);
return DList_Insert_Node_ByIndex(myStack->HeadNode, InsertNode, 1);
}

Ret Stack_Pop(Stack* myStack)
{
check_pointer_return_value(myStack, Ret_Fail);
// Beacuse nature of Stack, the node need to be popped out from the Noed which nearest Head Node.
return (DList_Delete_Node_ByIndex(myStack->HeadNode, 1));

}

Ret Queue_Get_Length(Stack* myStack, int* length)
{
check_pointer_return_value(myStack, Ret_Fail);
return DList_Get_Length(myStack->HeadNode, length);
}

Ret Stack_Get_Node(Stack* myStack, DList** RetNode)
{
check_pointer_return_value(myStack, Ret_Fail);

// Because the Nature of Stack, we alwasy get the first Node.
if ( Ret_Fail == DList_Get_Node_ByIndex(myStack->HeadNode, 1, RetNode))
{
SR_ERR("Fail to get Node from Stack \n");
return Ret_Fail;
}

}

2.DList.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "global_enum_macro.h"

typedef struct _DList
{
struct _DList* DList_Pre_Ptr;
struct _DList* DList_Next_Ptr;
void* data;
int key;
}DList;

DList* DList_Create(void);
Ret DList_Destroy(DList*);
typedef Ret (*DList_Print)(DList*);
Ret DList_Print_all(DList*, DList_Print);
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index);
Ret DList_Delete_Node_ByIndex(DList*, int index);
Ret DList_Get_NodeData_ByIndex(DList*, int index, void** data);
Ret DList_Get_Node_ByIndex(DList*, int index, DList**);
Ret DList_Get_Length(DList*, int* length);

3.DList.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#include "DList.h"
#include "stdlib.h"


DList* DList_Create(void)
{
// Create the Head Node for Double Link List
DList* HeadNode = (DList*)malloc(sizeof(DList));

check_pointer_return_value(HeadNode,NULL);

HeadNode->DList_Pre_Ptr = NULL;
HeadNode->DList_Next_Ptr = NULL;

return HeadNode;

}

Ret DList_Destroy(DList* HeadNode)
{

check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

DList* Temp_Ptr = HeadNode;

while (1)
{

if (HeadNode == NULL)
{
printf("Success to Destroy the Double Link List\n");
return Ret_Success;
}

HeadNode = HeadNode->DList_Next_Ptr;

free(Temp_Ptr->data);
free(Temp_Ptr);

Temp_Ptr = HeadNode;
}

}

Ret DList_Print_all(DList* HeadNode, DList_Print Print)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(Print, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

DList* DList_Ptr = HeadNode;

while (DList_Ptr->DList_Next_Ptr != NULL)
{
// if the node is HEAD, we skip that node
if (DList_Ptr->DList_Pre_Ptr != NULL)
{
Print(DList_Ptr);
}
DList_Ptr = DList_Ptr->DList_Next_Ptr;
}

// Print the Tail Node's data
Print(DList_Ptr);

}
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(InsertNode, Ret_Fail);

// check the Double Link List is EMPTY ??
if (HeadNode->DList_Pre_Ptr == NULL && HeadNode->DList_Next_Ptr == NULL)
{
HeadNode->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
InsertNode->DList_Pre_Ptr = HeadNode;
printf("Because the Double Link List is EMPTY, so I force the index to be 1 \n");
return Ret_Success;
}

int cnt=0;
DList* Temp_Ptr = HeadNode;

do
{
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (cnt == index)
{
InsertNode->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
InsertNode->DList_Pre_Ptr->DList_Next_Ptr = InsertNode;
Temp_Ptr->DList_Pre_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = Temp_Ptr;
return Ret_Success;
}

} while ( Temp_Ptr->DList_Next_Ptr != NULL);

// If the index is large than the length of Double link list, just add the NODE into the tail of Double Link List.

printf("Because the index is large than the length of Double Link List, just insert the NODE into the tail of Double LInke List \n");
Temp_Ptr->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
return Ret_Success;
}

Ret DList_Delete_Node_ByIndex(DList* HeadNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

int cnt=0;
DList* Temp_Ptr = HeadNode;
while (Temp_Ptr->DList_Next_Ptr != NULL)
{
if (cnt == index)
{
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = Temp_Ptr->DList_Next_Ptr;
Temp_Ptr->DList_Next_Ptr->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
printf("Free the Node of Indx[%d] \n", index);
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
}

// Because the index is large than the length of Double Link List && the Node which you want to delete is TAIL Node.

printf("Free the TAIL NODE \n");
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = NULL;
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}


Ret DList_Get_NodeData_ByIndex(DList* HeadNode, int index, void** data)
{
check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

int cnt=0;
DList* Temp_Ptr = HeadNode;
do
{
cnt++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (cnt == index || Temp_Ptr->DList_Next_Ptr == NULL)
{
if (Temp_Ptr->DList_Next_Ptr == NULL)
{
// Tail Node
printf("The index is larger than the length of Double Link List, so just get the data of Tail Node for you \n");
}
*data = (void*)(Temp_Ptr->data);
return Ret_Success;
}
} while(1);
}

Ret DList_Get_Node_ByIndex(DList* HeadNode, int index, DList** RetNode)
{

check_pointer_return_value(HeadNode, Ret_Fail);

int cnt = 0;
for (cnt = 0; cnt<=index; cnt++)
{
if (HeadNode->DList_Next_Ptr == NULL || cnt == index)
{
SR_DBG("This is the TAIL NODE or find the Node, so return NODE \n");
goto RETURN_DONE;
}
HeadNode = HeadNode->DList_Next_Ptr;
}

goto RETURN_DONE;

RETURN_DONE :
*RetNode = HeadNode;
return Ret_Success;
}

Ret DList_Get_Length(DList* HeadNode, int* length)
{

check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
*length = 0;
check_pointer_return_value(NULL, Ret_Success);
}

*length=0;
DList* Temp_Ptr = HeadNode;
do
{
(*length)++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (Temp_Ptr->DList_Next_Ptr == NULL)
{
return Ret_Success;
}
} while(1);


}

4.global_enum_macro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// Define GLobal Enum
typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None,
}Ret;

// Define Global Macro
#define SR_DBG(fmt,args ...) printf("[Sheldon debug][%s][%d] "fmt,__FUNCTION__,__LINE__,##args)
#define SR_ERR(fmt,args ...) printf("ERROR !!! [%s][%d ] "fmt, __FUNCTION__,__LINE__,##args)
#define check_pointer_return_value(ptr,value) if(ptr==NULL) \
{ printf("[%s][%d] ERROR!!! Pointer is NULL \r\n",__FUNCTION__,__LINE__); \
return value;} \

5.main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdlib.h>
#include "stack.h"

Ret MyPrint(DList* MyDList)
{
check_pointer_return_value(MyDList, Ret_Fail);
// This place tell how to print the DLinkList's data type
printf("MyDList->key=%d, *(int*)(MyDList->data)=%d \r\n", MyDList->key, *(int*)(MyDList->data));
}

DList* Create_Node(int data)
{
DList* myNode = (DList*)malloc(sizeof(DList));
myNode->data = (int*)malloc(sizeof(int));
*(int*)(myNode->data) = data;
return myNode;
}

void main(void)
{
Stack* myStack = Stack_Create() ;

// Push the Node to Queue
Stack_Push(myStack, Create_Node(10));
Stack_Push(myStack, Create_Node(20));
Stack_Push(myStack, Create_Node(30));
Stack_Push(myStack, Create_Node(40));
Stack_Push(myStack, Create_Node(50));

// Print all the Nodes of Queue
Stack_Print_all(myStack, MyPrint);

// Pop out the Node from Queue
// Test Stack_Get_Node
SR_DBG("=================\r\n");
DList* D_Ptr = NULL;
Stack_Get_Node(myStack, &D_Ptr);
SR_DBG("data is %d \r\n",*(int*)(D_Ptr->data));
SR_DBG(" Pop out Node\r\n");
Stack_Pop(myStack);
Stack_Get_Node(myStack, &D_Ptr);
SR_DBG("data is %d \r\n",*(int*)(D_Ptr->data));
SR_DBG(" Pop out Node\r\n");
Stack_Pop(myStack);
Stack_Get_Node(myStack, &D_Ptr);
SR_DBG("data is %d \r\n",*(int*)(D_Ptr->data));

// Print all the Nodes of Queue
Stack_Print_all(myStack, MyPrint);

// Destroy the Queue
if (Ret_Success == Stack_Destroy(myStack))
{
SR_DBG("Destroy Stack -- Success !!!\n");
myStack = NULL;
}

Stack_Print_all(myStack, MyPrint);

}

[VIM] Backup the setting of VIM

文章目錄
  1. Purpose
    1. .vimrc
    2. .vimrc.local
    3. sr

Purpose

最近感覺電腦快往生了,所以現在未雨愁繆,先將

自己常用的vim setting作一下備份,順便將ctag和cscope

常用的script作一下記錄,假如有人有興趣也可以拿去發揚光大.

.vimrc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
" set up pathogen, https://github.com/tpope/vim-pathogen
filetype on " without this vim emits a zero exit status, later, because of :ft off
filetype off
call pathogen#infect()
filetype plugin indent on
" don't bother with vi compatibility
set nocompatible

" enable syntax highlighting
syntax enable

" auto come back the last file location
if has("autocmd")
autocmd BufRead *.txt set tw=78
autocmd BufReadPost *
\ if line("'\"") > 0 && line ("'\"") <= line("$") |
\ exe "normal g'\"" |
\ endif
endif


let g:session_autosave = 'yes'

set autoindent
set autoread " reload files when changed on disk, i.e. via `git checkout`
set backspace=2 " Fix broken backspace in some setups
set backupcopy=yes " see :help crontab
set clipboard=unnamed " yank and paste with the system clipboard
set directory-=. " don't store swapfiles in the current directory
set encoding=utf-8
set expandtab " expand tabs to spaces
set ignorecase " case-insensitive search
set incsearch " search as you type
set laststatus=2 " always show statusline
set list " show trailing whitespace
set listchars=tab:▸\ ,trail:▫
set number " show line numbers
set ruler " show where you are
set scrolloff=3 " show context above/below cursorline
set shiftwidth=2 " normal mode indentation commands use 2 spaces
set showcmd
set smartcase " case-sensitive search if any caps
set softtabstop=2 " insert mode tab and backspace use 2 spaces
set tabstop=8 " actual tabs occupy 8 characters
set wildignore=log/**,node_modules/**,target/**,tmp/**,*.rbc
set wildmenu " show a navigable menu for tab completion
set wildmode=longest,list,full

set modifiable
set write
set hlsearch
set ic
set clipboard=unnamedplus
" Enable basic mouse behavior such as resizing buffers.
set mouse=a
if exists('$TMUX') " Support resizing in tmux
set ttymouse=xterm2
endif

" keyboard shortcuts
let mapleader = ','
map <C-h> <C-w>h
map <C-j> <C-w>j
map <C-k> <C-w>k
map <C-l> <C-w>l
map <leader>l :Align
nmap <leader>a :Ack
nmap <leader>b :CtrlPBuffer<CR>
nmap <leader>d :NERDTreeToggle<CR>
nmap <leader>f :NERDTreeFind<CR>
nmap <leader>t :CtrlP<CR>
nmap <leader>s :cs find c <C-R>=expand("<cword>")<CR><CR>
nmap <leader>e :cs find t <C-R>=expand("<cword>")<CR><CR>
nmap <leader>T :CtrlPClearCache<CR>:CtrlP<CR>
nmap <leader>] :TagbarToggle<CR>
nmap <leader><space> :call whitespace#strip_trailing()<CR>
nmap <leader>g :GitGutterToggle<CR>
nmap <leader>c <Plug>Kwbd
map <silent> <leader>V :source ~/.vimrc<CR>:filetype detect<CR>:exe ":echo 'vimrc reloaded'"<CR>

" NERDTree seeting
let NERDTreeShowHidden=1


"将:cs find
"c等Cscope查找命令映射为<C-_>c等快捷键(按法是先按Ctrl+Shift+-,然后很快再按下c)
"nmap <C-_>s :cs find s <C-R>=expand("<cword>")<CR><CR>:copen<CR><CR>
"nmap <C-_>g :cs find g <C-R>=expand("<cword>")<CR><CR>
"nmap <C-_>d :cs find d <C-R>=expand("<cword>")<CR><CR>:copen<CR><CR>
"nmap <C-_>c :cs find c <C-R>=expand("<cword>")<CR><CR>:copen<CR><CR>
"nmap <C-_>t :cs find t <C-R>=expand("<cword>")<CR><CR>:copen<CR><CR>
"nmap <C-_>e :cs find e <C-R>=expand("<cword>")<CR><CR>:copen<CR><CR>
"nmap <C-_>f :cs find f <C-R>=expand("<cfile>")<CR><CR>
"nmap <C-_>i :cs find i <C-R>=expand("<cfile>")<CR><CR>:copen<CR><CR>


" plugin settings
let g:ctrlp_match_window = 'order:ttb,max:20'
let g:NERDSpaceDelims=1
let g:gitgutter_enabled = 0

" Use The Silver Searcher https://github.com/ggreer/the_silver_searcher
if executable('ag')
let g:ackprg = 'ag --nogroup --column'

" Use Ag over Grep
set grepprg=ag\ --nogroup\ --nocolor

" Use ag in CtrlP for listing files. Lightning fast and respects .gitignore
let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'
endif

" fdoc is yaml
autocmd BufRead,BufNewFile *.fdoc set filetype=yaml
" md is markdown
autocmd BufRead,BufNewFile *.md set filetype=markdown
" extra rails.vim help
autocmd User Rails silent! Rnavcommand decorator app/decorators -glob=**/* -suffix=_decorator.rb
autocmd User Rails silent! Rnavcommand observer app/observers -glob=**/* -suffix=_observer.rb
autocmd User Rails silent! Rnavcommand feature features -glob=**/* -suffix=.feature
autocmd User Rails silent! Rnavcommand job app/jobs -glob=**/* -suffix=_job.rb
autocmd User Rails silent! Rnavcommand mediator app/mediators -glob=**/* -suffix=_mediator.rb
autocmd User Rails silent! Rnavcommand stepdefinition features/step_definitions -glob=**/* -suffix=_steps.rb
" automatically rebalance windows on vim resize
autocmd VimResized * :wincmd =

" Fix Cursor in TMUX
if exists('$TMUX')
let &t_SI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=1\x7\<Esc>\\"
let &t_EI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=0\x7\<Esc>\\"
else
let &t_SI = "\<Esc>]50;CursorShape=1\x7"
let &t_EI = "\<Esc>]50;CursorShape=0\x7"
endif

" Go crazy!
if filereadable(expand("~/.vimrc.local"))
" In your .vimrc.local, you might like:
"
" set autowrite
" set nocursorline
" set nowritebackup
" set whichwrap+=<,>,h,l,[,] " Wrap arrow keys between lines
"
" autocmd! bufwritepost .vimrc source ~/.vimrc
" noremap! jj <ESC>
source ~/.vimrc.local
endif

.vimrc.local

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
"set nocursorline " don't highlight current line
set cursorline

" keyboard shortcuts
inoremap jj <ESC>

" gui settings
if (&t_Co == 256 || has('gui_running'))
if ($TERM_PROGRAM == 'iTerm.app')
colorscheme solarized
else
colorscheme desert
endif
endif
"""
" Cscope settings
if has("cscope")
let i = 1
let path_depth = 20
while i < path_depth
if filereadable("cscope.out")
let db = getcwd() . "/cscope.out"
echo db
let $CSCOPE_DB = db
cs add $CSCOPE_DB
let i = 20
else
cd ..
let i += 1
endif
endwhile
endif

sr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/sh
FILE_LIST=file_list
temp_str=NULL

for i in "$@"
do
if [ -n "$i" ]; then
temp_str=$i
if [ "$1" = "$i" ]; then
echo "First Source code directory :" "$1"
find $i -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.mk" -o -name "*config" -o -name "Makefile" -o -name "*.inl" -o -name "*.py" > ./$FILE_LIST
else
echo "the other source code directory :" "$i"
find $i -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.mk" -o -name "*config" -o -name "Makefile" -o -name "*.inl" -o -name "*.py" >> ./$FILE_LIST
fi
else
echo "please keyin the project path"
fi
done

if [ "$#" -ne 0 ]; then
echo "create the cscope tag and ctags"
cscope -bkq -i ./$FILE_LIST
ctags -R -L ./$FILE_LIST
fi

[Queue] Create the Queue structure by the Double Link List

文章目錄
  1. Purpose
  2. Explain the conecpt of the Queue Structure.
  3. FULL CODE

Purpose

爲了鍛鍊自己的能力,所以就是想寫點東西,看到別人用雙向鏈接兜出了

一個queue 的結構,自己也想無中生有的產生一個出來.前一篇已經有完成了

雙向鏈結,這篇就有點想是表現組合的威力.基本上無論是queue或是stack

都是雙向鏈結的特例,所以真是基礎打的好,什麼都能迎刃而解.

Explain the conecpt of the Queue Structure.

Queue 其實就是先進先出.我們只有多包一層API,強迫caller使用API的時候,

Push都是將雙向鏈結的Node,推在前端,讓後將原本在queue 裏面的往後移.

Pop的話,就單純將queue裏面最後一個雙向鏈結的Node移除.

槪念相當單純,由於我在雙向鏈結的實作,將Node所存的type,交給caller來決定,

所以在Queue 的 Demo code裏面,也是沿用這樣的概念.

根據如何操作Queue,所以我開了底下這些API,

實際如何包就請參考擺在最後面的code.

1
2
3
4
5
6
Queue* Queue_Create(void);
Ret Queue_Destroy(Queue*);
Ret Queue_Print_all(Queue*, DList_Print);
Ret Queue_Push(Queue*, DList* InsertNode);
Ret Queue_Pop(Queue*);
Ret Queue_Get_Length(Queue*, int* length);

由於Queue其實就是雙向鏈接的特例,所以結構上就是跟雙向鏈結一樣

只是會限制他的操作,所以Queue的結構就定義成底下

1
2
3
4
typedef struct _Queue
{
DList* HeadNode;
}Queue;

FULL CODE

1. queue.h

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "DList.h"

typedef struct _Queue
{
DList* HeadNode;
}Queue;

Queue* Queue_Create(void);
Ret Queue_Destroy(Queue*);
Ret Queue_Print_all(Queue*, DList_Print);
Ret Queue_Push(Queue*, DList* InsertNode);
Ret Queue_Pop(Queue*);
Ret Queue_Get_Length(Queue*, int* length);

2.queue.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <stdlib.h>
#include "queue.h"

Queue* Queue_Create(void)
{
Queue* myQueue = (Queue*)malloc(sizeof(Queue));
check_pointer_return_value(myQueue, NULL);

myQueue->HeadNode = DList_Create();
return myQueue;
}

Ret Queue_Destroy(Queue* myQueue)
{
check_pointer_return_value(myQueue, Ret_Fail);
if ( Ret_Fail == DList_Destroy( myQueue->HeadNode) )
{
SR_ERR("DList_Destroy FAILLL\n");
return Ret_Fail;
}
SR_DBG("Free the QUEUE\n");
free(myQueue);
return Ret_Success;
}

Ret Queue_Print_all(Queue* myQueue, DList_Print Print)
{
check_pointer_return_value(myQueue, Ret_Fail);
return DList_Print_all(myQueue->HeadNode, Print);
}

Ret Queue_Push(Queue* myQueue, DList* InsertNode)
{
// I think the Head Node doesn't belong to be the Data Node.
check_pointer_return_value(myQueue, Ret_Fail);
return DList_Insert_Node_ByIndex(myQueue->HeadNode, InsertNode, 1);
}

Ret Queue_Pop(Queue* myQueue)
{
check_pointer_return_value(myQueue, Ret_Fail);
int length =0;
if (Ret_Fail == DList_Get_Length(myQueue->HeadNode, &length))
{
SR_ERR("Get the Length of DList \n");
return Ret_Fail;
}

return (DList_Delete_Node_ByIndex(myQueue->HeadNode, length));

}

Ret Queue_Get_Length(Queue* myQueue, int* length)
{
check_pointer_return_value(myQueue, Ret_Fail);
return DList_Get_Length(myQueue->HeadNode, length);
}

3.DList.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "global_enum_macro.h"

typedef struct _DList
{
struct _DList* DList_Pre_Ptr;
struct _DList* DList_Next_Ptr;
void* data;
int key;
}DList;

DList* DList_Create(void);
Ret DList_Destroy(DList*);
typedef Ret (*DList_Print)(DList*);
Ret DList_Print_all(DList*, DList_Print);
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index);
Ret DList_Delete_Node_ByIndex(DList*, int index);
Ret DList_Get_NodeData_ByIndex(DList*, int index, void** data);
Ret DList_Get_Length(DList*, int* length);

4.DList.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include "DList.h"
#include "stdlib.h"


DList* DList_Create(void)
{
// Create the Head Node for Double Link List
DList* HeadNode = (DList*)malloc(sizeof(DList));

check_pointer_return_value(HeadNode,NULL);

HeadNode->DList_Pre_Ptr = NULL;
HeadNode->DList_Next_Ptr = NULL;

return HeadNode;

}

Ret DList_Destroy(DList* HeadNode)
{

check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

DList* Temp_Ptr = HeadNode;

while (1)
{
if (HeadNode == NULL)
{
printf("Success to Destroy the Double Link List\n");
return Ret_Success;
}

HeadNode = HeadNode->DList_Next_Ptr;

free(Temp_Ptr->data);
free(Temp_Ptr);

Temp_Ptr = HeadNode;
}

}

Ret DList_Print_all(DList* HeadNode, DList_Print Print)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(Print, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

DList* DList_Ptr = HeadNode;

while (DList_Ptr->DList_Next_Ptr != NULL)
{
// if the node is HEAD, we skip that node
if (DList_Ptr->DList_Pre_Ptr != NULL)
{
Print(DList_Ptr);
}
DList_Ptr = DList_Ptr->DList_Next_Ptr;
}

// Print the Tail Node's data
Print(DList_Ptr);

}
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(InsertNode, Ret_Fail);

// check the Double Link List is EMPTY ??
if (HeadNode->DList_Pre_Ptr == NULL && HeadNode->DList_Next_Ptr == NULL)
{
HeadNode->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
InsertNode->DList_Pre_Ptr = HeadNode;
printf("Because the Double Link List is EMPTY, so I force the index to be 1 \n");
return Ret_Success;
}

int cnt=0;
DList* Temp_Ptr = HeadNode;

do
{
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (cnt == index)
{
InsertNode->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
InsertNode->DList_Pre_Ptr->DList_Next_Ptr = InsertNode;
Temp_Ptr->DList_Pre_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = Temp_Ptr;
return Ret_Success;
}

} while ( Temp_Ptr->DList_Next_Ptr != NULL);

// If the index is large than the length of Double link list, just add the NODE into the tail of Double Link List.

printf("Because the index is large than the length of Double Link List, just insert the NODE into the tail of Double LInke List \n");
Temp_Ptr->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
return Ret_Success;
}

Ret DList_Delete_Node_ByIndex(DList* HeadNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

int cnt=0;
DList* Temp_Ptr = HeadNode;
while (Temp_Ptr->DList_Next_Ptr != NULL)
{
if (cnt == index)
{
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = Temp_Ptr->DList_Next_Ptr;
Temp_Ptr->DList_Next_Ptr->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
printf("Free the Node of Indx[%d] \n", index);
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
}

// Because the index is large than the length of Double Link List && the Node which you want to delete is TAIL Node.

printf("Free the TAIL NODE \n");
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = NULL;
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}


Ret DList_Get_NodeData_ByIndex(DList* HeadNode, int index, void** data)
{
check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

int cnt=0;
DList* Temp_Ptr = HeadNode;
do
{
cnt++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (cnt == index || Temp_Ptr->DList_Next_Ptr == NULL)
{
if (Temp_Ptr->DList_Next_Ptr == NULL)
{
// Tail Node
printf("The index is larger than the length of Double Link List, so just get the data of Tail Node for you \n");
}
*data = (void*)(Temp_Ptr->data);
return Ret_Success;
}
} while(1);
}

Ret DList_Get_Length(DList* HeadNode, int* length)
{

check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
*length = 0;
check_pointer_return_value(NULL, Ret_Success);
}

*length=0;
DList* Temp_Ptr = HeadNode;
do
{
(*length)++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (Temp_Ptr->DList_Next_Ptr == NULL)
{
return Ret_Success;
}
} while(1);


}

5.global_enum_macro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// Define GLobal Enum
typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None,
}Ret;

// Define Global Macro
#define SR_DBG(fmt,args ...) printf("[Sheldon debug][%s][%d] "fmt,__FUNCTION__,__LINE__,##args)
#define SR_ERR(fmt,args ...) printf("ERROR !!! [%s][%d ] "fmt, __FUNCTION__,__LINE__,##args)
#define check_pointer_return_value(ptr,value) if(ptr==NULL) \
{ printf("[%s][%d] ERROR!!! #ptr# is NULL, return #value# \r\n",__FUNCTION__,__LINE__); \
return value;} \

6.main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdlib.h>
#include "queue.h"

Ret MyPrint(DList* MyDList)
{
check_pointer_return_value(MyDList, Ret_Fail);
// This place tell how to print the DLinkList's data type
printf("MyDList->key=%d, *(int*)(MyDList->data)=%d \r\n", MyDList->key, *(int*)(MyDList->data));
}

DList* Create_Node(int data)
{
DList* myNode = (DList*)malloc(sizeof(DList));
myNode->data = (int*)malloc(sizeof(int));
*(int*)(myNode->data) = data;
return myNode;
}

void main(void)
{
Queue* myQueue = Queue_Create() ;

// Push the Node to Queue
Queue_Push(myQueue, Create_Node(10));
Queue_Push(myQueue, Create_Node(20));
Queue_Push(myQueue, Create_Node(30));
Queue_Push(myQueue, Create_Node(40));
Queue_Push(myQueue, Create_Node(50));

// Print all the Nodes of Queue
Queue_Print_all(myQueue, MyPrint);

// Pop out the Node from Queue
Queue_Pop(myQueue);
Queue_Pop(myQueue);

// Print all the Nodes of Queue
Queue_Print_all(myQueue, MyPrint);

// Destroy the Queue
if (Ret_Success == Queue_Destroy(myQueue))
{
SR_DBG("Destroy Queue -- Success !!!\n");
myQueue = NULL;
}

Queue_Print_all(myQueue, MyPrint);

}

[C][DB][Double Link List] Exercise the Double Link List

文章目錄
  1. Purpose
  2. Explain what I DO
    1. Concept
    2. FULL CODE

Purpose

最近好奇要怎麼實作Stack 和 queue,看了一本書,他是用double link list來實作,

爲了要自我鍛鍊一下,所以自己寫了一個double link list的實作.

之後,會再補上stack/heap的組合變化.

Explain what I DO

Concept

1. DList.h

我將API 對外的function都放在這裏.

基本上就是產生一個D_Link_List,和Print D_Link_List, 新增刪除Node.

新增和刪除node的方式,就是參考index. index 你可以把當作D_Link_List的Node個數

我現在實作的D_Link_List 最少有一個Head Node, index可以把他當作是0.

1
2
3
4
5
DList* DList_Create(void);
typedef Ret (*DList_Print)(DList*);
Ret DList_Print_all(DList*, DList_Print);
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index);
Ret DList_Delete_Node_ByIndex(DList*, int index);

在DList 的struct裏面, 我特意將data 存成 pointer to void. 目的其實,就是由上層來決定Double Link List裏面的Node,資料是存什麼.

1
2
3
4
5
6
7
typedef struct _DList
{
struct _DList* DList_Pre_Ptr;
struct _DList* DList_Next_Ptr;
void* data;
int key;
}DList;

2.DList.c

大部分實作放在這裏.

3. main.c

由於我把data要存什麼type,交給上層來決定, 所以必須要實作存data和display data的function. 可以參考底下這兩個function,所以我要換Node 的data type也會非常方便.

1
2
Ret MyPrint(DList* MyDList);
DList* Create_Node(int data);

我在DList struct 裏面多存了一個key的東西,爲了日後方便,可以search關鍵字. 就可以找到你要的node,但是API還沒寫好.現在只支援Index的方式.XD

在main的後面,有多補一些測試的部分.

FULL CODE

1. DList.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include "global_enum_macro.h"

typedef struct _DList
{
struct _DList* DList_Pre_Ptr;
struct _DList* DList_Next_Ptr;
void* data;
int key;
}DList;

DList* DList_Create(void);
typedef Ret (*DList_Print)(DList*);
Ret DList_Print_all(DList*, DList_Print);
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index);
Ret DList_Delete_Node_ByIndex(DList*, int index);

2. DList.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "DList.h"
#include "stdlib.h"


DList* DList_Create(void)
{
// Create the Head Node for Double Link List
DList* HeadNode = (DList*)malloc(sizeof(DList));

check_pointer_return_value(HeadNode,NULL);

HeadNode->DList_Pre_Ptr = NULL;
HeadNode->DList_Next_Ptr = NULL;

return HeadNode;

}

Ret DList_Print_all(DList* HeadNode, DList_Print Print)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(Print, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

DList* DList_Ptr = HeadNode;

while (DList_Ptr->DList_Next_Ptr != NULL)
{
// if the node is HEAD, we skip that node
if (DList_Ptr->DList_Pre_Ptr != NULL)
{
Print(DList_Ptr);
}
DList_Ptr = DList_Ptr->DList_Next_Ptr;
}

// Print the Tail Node's data
Print(DList_Ptr);

}
Ret DList_Insert_Node_ByIndex(DList* HeadNode, DList* InsertNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);
check_pointer_return_value(InsertNode, Ret_Fail);

// check the Double Link List is EMPTY ??
if (HeadNode->DList_Pre_Ptr == NULL && HeadNode->DList_Next_Ptr == NULL)
{
HeadNode->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
InsertNode->DList_Pre_Ptr = HeadNode;
printf("Because the Double Link List is EMPTY, so I force the index to be 1 \n");
return Ret_Success;
}

int cnt=0;
DList* Temp_Ptr = HeadNode;

do
{
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
if (cnt == index)
{
InsertNode->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
InsertNode->DList_Pre_Ptr->DList_Next_Ptr = InsertNode;
Temp_Ptr->DList_Pre_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = Temp_Ptr;
return Ret_Success;
}

} while ( Temp_Ptr->DList_Next_Ptr != NULL);

// If the index is large than the length of Double link list, just add the NODE into the tail of Double Link List.

printf("Because the index is large than the length of Double Link List, just insert the NODE into the tail of Double LInke List \n");
Temp_Ptr->DList_Next_Ptr = InsertNode;
InsertNode->DList_Next_Ptr = NULL;
return Ret_Success;
}

Ret DList_Delete_Node_ByIndex(DList* HeadNode, int index)
{
check_pointer_return_value(HeadNode, Ret_Fail);

// Check the Double Link List is only Head Node ?
if (HeadNode->DList_Next_Ptr == NULL && HeadNode->DList_Pre_Ptr == NULL)
{
printf("The Double Link List Is EMPTY \n");
check_pointer_return_value(NULL, Ret_Fail);
}

int cnt=0;
DList* Temp_Ptr = HeadNode;
while (Temp_Ptr->DList_Next_Ptr != NULL)
{
if (cnt == index)
{
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = Temp_Ptr->DList_Next_Ptr;
Temp_Ptr->DList_Next_Ptr->DList_Pre_Ptr = Temp_Ptr->DList_Pre_Ptr;
printf("Free the Node of Indx[%d] \n", index);
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}
cnt ++;
Temp_Ptr = Temp_Ptr->DList_Next_Ptr;
}

// Because the index is large than the length of Double Link List && the Node which you want to delete is TAIL Node.

printf("Free the TAIL NODE \n");
Temp_Ptr->DList_Pre_Ptr->DList_Next_Ptr = NULL;
free(Temp_Ptr->data);
free(Temp_Ptr);
return Ret_Success;
}

3.main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdlib.h>
#include "DList.h"

Ret MyPrint(DList* MyDList)
{
check_pointer_return_value(MyDList, Ret_Fail);
// This place tell how to print the DLinkList's data type
printf("MyDList->key=%d, *(int*)(MyDList->data)=%d \r\n", MyDList->key, *(int*)(MyDList->data));
}

DList* Create_Node(int data)
{
DList* myNode = (DList*)malloc(sizeof(DList));
myNode->data = (int*)malloc(sizeof(int));
*(int*)(myNode->data) = data;
return myNode;
}

void main(void)
{
DList* HeadNode = DList_Create();

// Create Node && Insert to the Double Link List
DList_Insert_Node_ByIndex(HeadNode,Create_Node(10),1);
DList_Insert_Node_ByIndex(HeadNode,Create_Node(20),1);
DList_Insert_Node_ByIndex(HeadNode,Create_Node(30),1);
DList_Insert_Node_ByIndex(HeadNode,Create_Node(40),3);
DList_Insert_Node_ByIndex(HeadNode,Create_Node(50),1);

// Delete the Node
DList_Delete_Node_ByIndex(HeadNode, 2);
DList_Delete_Node_ByIndex(HeadNode, 5);
DList_Delete_Node_ByIndex(HeadNode, 1);

// Print all the Nodes of Double Link List
DList_Print_all(HeadNode, MyPrint);
}

4.global_enum_macro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// Define GLobal Enum
typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None,
}Ret;

// Define Global Macro
#define SR_DBG(fmt,args ...) printf("[Sheldon debug][%s][%d] "fmt,__FUNCTION__,__LINE__,##args)
#define SR_ERR(fmt,args ...) printf("ERROR !!! [%s][%d ] "fmt, __FUNCTION__,__LINE__,##args)
#define check_pointer_return_value(ptr,value) if(ptr==NULL) \
{ printf("ERROR!!! #ptr is NULL, return #value \r\n"); \
return value;} \

[Read/Write Lock][Mutex] exercise to implement the read/write lock in the mutex

文章目錄
  1. 目的
  2. Sample Code.

目的

最近遇到一個問題,假如你現在程式裏面有許多thread,每個thread會存取相同的資料,

一般來說,我們都會用mutex來做保護,避免讀資料的thread,再讀的時候,寫資料的thread就把資料改過了

以致於讀資料的thread,拿到錯誤的資訊.

但是假如程式裏面,大部分的thread都是讀資料,寫資料的thread其實不是很多,這樣的話,我們都用同一個mutex的話,

效率其實會下降,所以就有人提出了read/write lock,兩個鎖的方式,讀資料的thread們,除了第一個讀的thread要等以外

其他的都不用.利害吧XDD.

Sample Code.

這份sample code,

  1. 我將最原本的mutex_lock實作擺在 basic_mutex_class.c, 而lock_interface.c 裡面有抽象的描述.

  2. 有關 Read/Write Lock 的實作擺在 main.c. 其實也只是多生出兩個mutex, 稱作讀鎖以及寫鎖. 在實作出讀寫鎖的使用方式.

a. main,c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include <stdlib.h>
#include "lock_interface.h"
#include "basic_mutex_class.h"


Ret read_RW_lock_ipl(read_write_lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

// 再來Read Lock 來保護read_count
if (api_my_lock(my_lock->RLock) == Ret_Success)
{
// 有thread 要讀的時候,read_count++, 記錄有幾個thread 還在用.
my_lock->read_count++;

// 嘗試獲得Write Lock, 禁止有人寫
if (api_my_lock(my_lock->WLock) == Ret_Success)
{
// 記錄現在lock mode 爲read.
my_lock->lock_mode = Read_Lock_Mode;
}
// UnLock 掉read lock, 由於只有讀的時候,不需要lock read thread.
if (api_my_unlock(my_lock->RLock) == Ret_Fail)
{
SR_ERR("\n");
return Ret_Fail;
}
}
}

Ret write_RW_lock_ipl(read_write_lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

// 嘗試獲得Write Lock, 禁止有人寫
if (api_my_lock(my_lock->WLock) == Ret_Success)
{
// 記錄現在lock mode 爲write.
my_lock->lock_mode = Write_Lock_Mode;
return Ret_Success;
}
return Ret_Fail;
}

Ret un_RW_lock_ipl(read_write_lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

if (my_lock->lock_mode == Read_Lock_Mode)
{
// 現在是讀的情況,需要要解鎖
// 用read lock 來保護read_count
if (api_my_lock(my_lock->RLock) == Ret_Success)
{
//檢查 read_count 是否爲0
my_lock->read_count--;
if (my_lock->read_count == 0)
{
// 由於現在已經沒有讀資料的thread了, 所以就是釋放Write Lock
if (api_my_unlock(my_lock->WLock)==Ret_Fail)
{
SR_ERR("\n");
return Ret_Fail;
}
}
if (api_my_unlock(my_lock->RLock) == Ret_Fail)
{
SR_ERR("\n");
return Ret_Fail;
}

SR_DBG("Success to unlock \n");
return Ret_Success;
}
}
else if (my_lock->lock_mode == Write_Lock_Mode)
{
// 寫的thread, 結束以後,解鎖
if (api_my_unlock(my_lock->WLock)==Ret_Fail)
{
SR_ERR("\n");
return Ret_Fail;
}
return Ret_Success;
}
else
{
SR_ERR("Lock Mode is Non, there is something wrong.... ");
}
}

Ret destroy_RW_lock_ipl(read_write_lock* my_lock)
{

check_pointer_return_value(my_lock, Ret_Fail);
free(my_lock->RLock);
free(my_lock->WLock);
free(my_lock);
SR_DBG("Success to destory read/write lock \n");
}

read_write_lock* create_read_write_lock(void)
{
read_write_lock* my_read_write_lock = malloc(sizeof(read_write_lock));

check_pointer_return_value(my_read_write_lock, NULL);

my_read_write_lock->read_count = 0;
my_read_write_lock->RLock = (My_Lock*)Init_Mutex_Pthread();
my_read_write_lock->WLock = (My_Lock*)Init_Mutex_Pthread();
my_read_write_lock->lock_mode = None_Lock_Mode;
my_read_write_lock->read_lock_Fun = read_RW_lock_ipl;
my_read_write_lock->write_lock_Fun = write_RW_lock_ipl;
my_read_write_lock->un_read_write_lock = un_RW_lock_ipl;
my_read_write_lock->destroy_read_write_lock = destroy_RW_lock_ipl;

return my_read_write_lock;
}

void main(void)
{

read_write_lock* my_RW_lock = create_read_write_lock();
// Test for Read lock
my_RW_lock->read_lock_Fun(my_RW_lock);
my_RW_lock->un_read_write_lock(my_RW_lock);

// Test for write lock
my_RW_lock->write_lock_Fun(my_RW_lock);
my_RW_lock->un_read_write_lock(my_RW_lock);

my_RW_lock->destroy_read_write_lock(my_RW_lock);

}

b.basic_mutex_class.h

1
2
3
4
5
6
7
8
9
10
11
#include <pthread.h>

My_Lock* Init_Mutex_Pthread(void);
Ret Mutex_Pthread_lock(My_Lock* );
Ret Mutex_Pthread_unlock(My_Lock* );
Ret Mutex_Pthread_destory(My_Lock* );

typedef struct _mutex_info
{
pthread_mutex_t mutex;
}mutex_info;

c.basic_mutex_class.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <stdlib.h>
#include "lock_interface.h"
#include "basic_mutex_class.h"

Ret Mutex_Pthread_lock(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

mutex_info* my_mutex = (mutex_info*)my_lock->lock_info;

if (pthread_mutex_lock(&my_mutex->mutex) == 0)
{
return Ret_Success;
}
else
{
SR_ERR("\n");
}
}

Ret Mutex_Pthread_unlock(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

mutex_info* my_mutex = (mutex_info*)my_lock->lock_info;

if (pthread_mutex_unlock(&my_mutex->mutex) == 0)
{
return Ret_Success;
}
else
{
SR_ERR("\n");
}
}

Ret Mutex_Pthread_destory(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

mutex_info* my_mutex = (mutex_info*)my_lock->lock_info;

if (pthread_mutex_destroy(&my_mutex->mutex) == 0)
{
free(my_lock);
return Ret_Success;
}
else
{
SR_ERR("\n");
}
}

My_Lock* Init_Mutex_Pthread(void)
{
My_Lock* my_lock = malloc(sizeof(My_Lock)+sizeof(mutex_info));
check_pointer_return_value(my_lock, NULL);

mutex_info* my_mutex;
my_mutex = (mutex_info*)my_lock->lock_info;
pthread_mutex_init(&(my_mutex->mutex),NULL);

my_lock->DoLock = Mutex_Pthread_lock;
my_lock->DoUnlock = Mutex_Pthread_unlock;
my_lock->DoDestory = Mutex_Pthread_destory;

return my_lock;

}

d.global_enum_macro.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

// Define GLobal Enum
typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None,
}Ret;

// Define Global Macro
#define SR_DBG(fmt,args ...) printf("[Sheldon debug][%s][%d] "fmt,__FUNCTION__,__LINE__,##args)
#define SR_ERR(fmt,args ...) printf("ERROR !!! [%s][%d ] "fmt, __FUNCTION__,__LINE__,##args)
#define check_pointer_return_value(ptr,value) if(ptr==NULL) \
{ printf("ERROR!!! #ptr is NULL, return #value \r\n"); \
return value;} \

e.lock_inter_face.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "global_enum_macro.h"

// For basic lock
struct _my_lock;
typedef struct _my_lock My_lock;

typedef Ret (*LockFun)(My_lock*);
typedef Ret (*UnLockFun)(My_lock*);
typedef Ret (*DestoryLockFun)(My_lock*);

typedef struct _my_lock
{
LockFun DoLock;
UnLockFun DoUnlock;
DestoryLockFun DoDestory;
char lock_info[0];
}My_Lock;


// For read/write lock
struct _read_write_lock;
typedef struct _read_write_lock read_write_lock;
typedef Ret (*ReadLockFun)(read_write_lock*);
typedef Ret (*WriteLockFun)(read_write_lock*);
typedef Ret (*UnReadWriteLockFun)(read_write_lock*);
typedef Ret (*DestroyReadWriteLockFun)(read_write_lock*);

typedef enum _ReadWriteLockMode
{
Read_Lock_Mode,
Write_Lock_Mode,
None_Lock_Mode,
}ReadWriteLockMode;


typedef struct _read_write_lock
{
int read_count;
My_Lock* RLock;
My_Lock* WLock;

ReadWriteLockMode lock_mode;
ReadLockFun read_lock_Fun;
WriteLockFun write_lock_Fun;
UnReadWriteLockFun un_read_write_lock;
DestroyReadWriteLockFun destroy_read_write_lock;
}read_write_lock;

Ret api_my_lock(My_Lock* my_lock);
Ret api_my_unlock(My_Lock* my_lock);
Ret api_my_destory(My_Lock* my_lock);

f.lock_interface.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "lock_interface.h"


Ret api_my_lock(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);
if (my_lock->DoLock(my_lock) == Ret_Fail)
{
SR_ERR("\n");
}
return Ret_Success;
}

Ret api_my_unlock(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);
if (my_lock->DoUnlock(my_lock) == Ret_Fail)
{
SR_ERR("\n");
}
return Ret_Success;
}

Ret api_my_destory(My_Lock* my_lock)
{
check_pointer_return_value(my_lock, Ret_Fail);

if (my_lock->DoDestory(my_lock) == Ret_Fail)
{
SR_ERR("\n");
}
return Ret_Success;
}

[C][Mutex][Pthread][Interface] A sample code for pthread_mutex interface

文章目錄
  1. Purpose
  2. The Concept of Sample Code
  3. Sample Code
  4. How to compiler
  5. [GDB練習] 覺得有趣的事情,

Purpose

今天閱讀到一個章節,是在說明同步的,thread之間的同步一般都會提到mutex,

讓不同thread之間能夠共用share資源,但是又不會干擾對方的state, 就非常重要了.

其中有個地方提到了,interface 的概念, 假如我的code是想要跑在各種平臺上面的話,我就應該將程式架構分成AP層, interface 層(API),

driver 層(偏硬體控制HW, 我們這邊就暫時不考慮它,embedded system 就很重要了) .

這邊的API層,提到了用大量的callback function,來達到跨平臺的需求,交由上層AP來決定,要運行在什麼平臺上.

底下的sample code, 是用pthread_mutex 來說明這個概念.

The Concept of Sample Code

假如我們需要把mutex 這種東西實作成一個interface,要如何去做,又能滿足各種平臺.

1. 抽象話

第一個要做的是讓mutex 變得抽象話, 實作的部分,都透過用calback的方式讓AP層來實作. 這樣聽起來有點像是在C用struct 取代C++的class XDD... 可參考 mutex_interface.h

1
2
3
4
5
6
7
struct _Locker 
{
LockerLockFunc lock;
LockerUnLockFunc unlock;
LockerDestoryLockFunc destory;
char lock_info[0];
};

這邊定了三個function pointer, 還有一個lock_info 來定義我們這個lock的特性. char lock_info[0], 這個宣告其實是一個技巧, char lock_info[0]其實並沒有佔任何空間, 假如你的私有資料長度是可變的,你就可以這樣宣告.

後面在create lock 的時候,會有提到如何做這件事情,

2. Create_Lock

爲什麼interface 沒有開出Create_Lock 的API給別任用呢, 書中提到, 這是因爲當你再做抽象話的描述時,你無法用 抽象畫來產生一個真實的實體出來,這句話我到現在還沒體會XDD.

3. Callback fucntion的引數都含有struct Locker

這個就是抽象話的好處,交由上層來決定我的實作方式,假如你是要用linux 的pthread_mutex 來實作的話. 請把這個東西的function pointer交給interface. 你看看mutex_interface.c 這個檔案,看官,是不是,多麼的清楚間單.

Sample Code

1.main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <pthread.h>
#include "mutex_interface.h"

Ret PthreadLock(Locker* thiz);
Ret PthreadUnLock(Locker* thiz);
Ret PthreadDestory(Locker* thiz);


typedef struct _pthread_info
{
pthread_mutex_t mutex_id;
} pthread_info;

Ret PthreadLock(Locker* thiz)
{
check_ptr(thiz, Ret_Fail);

pthread_info* pp_info = (pthread_info*)thiz->lock_info;
if ( 0 == pthread_mutex_lock(&pp_info->mutex_id))
{
return Ret_Success;
}
else
{
SR_DBG("WTF!!! ERROR !!!\r\n");
return Ret_Fail;
}

}

Ret PthreadUnLock(Locker* thiz)
{
check_ptr(thiz, Ret_Fail);

pthread_info* pp_info = (pthread_info*)thiz->lock_info;
if ( 0 == pthread_mutex_unlock(&pp_info->mutex_id))
{
return Ret_Success;
}
else
{
SR_DBG("WTF!!! ERROR !!!\r\n");
return Ret_Fail;
}
}

Ret PthreadDestory(Locker* thiz)
{
check_ptr(thiz, Ret_Fail);

pthread_info* pp_info = (pthread_info*)thiz->lock_info;

if ( 0 != pthread_mutex_destroy(&pp_info->mutex_id))
{
return Ret_Fail;
}
SR_DBG("FREE the mutex \n");
free(thiz);
return Ret_Success;
}

Locker* create_locker(void)
{
SR_DBG("Start \n\r");
// Allocate the memory for locker
Locker* locker_thiz = malloc(sizeof(Locker) + sizeof(pthread_info));
pthread_info* pp_info = (pthread_info*)locker_thiz->lock_info;

if (NULL != locker_thiz)
{
// Init the callback function in class.
locker_thiz->lock = PthreadLock;
locker_thiz->unlock = PthreadUnLock;
locker_thiz->destory = PthreadDestory;
pthread_mutex_init(&(pp_info->mutex_id),NULL);
return locker_thiz;
}
return NULL;
}


void main(void)
{
Locker* myLocker ;
myLocker = create_locker();

myLocker->destory(myLocker);
}

2.mutex_interface.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "mutex_interface.h"

Ret locker_lock(Locker* thiz)
{
check_ptr(thiz,Ret_Fail);

return thiz->lock(thiz);
}

Ret locker_unlock(Locker* thiz)
{
check_ptr(thiz,Ret_Fail);

return thiz->unlock(thiz);
}

Ret locker_destory(Locker* thiz)
{
check_ptr(thiz,Ret_Fail);

return thiz->destory(thiz);
}

3.mutex_interface.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <stdio.h>
#include <stdlib.h>

struct _Locker;
typedef struct _Locker Locker;

typedef enum _Ret
{
Ret_Success,
Ret_Fail,
Ret_None
}Ret;

typedef Ret (*LockerLockFunc)(Locker* thiz);
typedef Ret (*LockerUnLockFunc)(Locker* thiz);
typedef Ret (*LockerDestoryLockFunc)(Locker* thiz);

struct _Locker
{
LockerLockFunc lock;
LockerUnLockFunc unlock;
LockerDestoryLockFunc destory;
char lock_info[0];
};


Ret locker_lock(Locker* thiz);
Ret locker_unlock(Locker* thiz);
Ret locker_destory(Locker* thiz);


#define check_ptr(ptr, var) if(ptr==NULL) \
{ printf(" ["#ptr"] pointer is NULL\r\n"); \
return var; } \

#define SR_DBG(fmt, arg...) printf("Sheldon Debug:[%s][%d]"fmt, __FUNCTION__, __LINE__, ##arg)

How to compiler

1
gcc -g main.c mutex_interface.c -lpthread -o main

[GDB練習] 覺得有趣的事情,

不知道各位有沒有注意到底下這兩行程式.

1
2
3
// Allocate the memory for locker
Locker* locker_thiz = malloc(sizeof(Locker) + sizeof(pthread_info));
pthread_info* pp_info = (pthread_info*)locker_thiz->lock_info;

這個地方就是剛剛提到的,若是一個可變的資料的話,要怎麼做呢. 分配locker_thiz指向的實體記憶體的時候,要多分配一塊 sizeof(pthread_info),這個就是user自定的. 看起來是不是很方便呢.XDDD

不知道大家有沒有宜個疑問,爲什麼locker_thiz->lock_info,是代表pp_info指向的位置呢.

底下是用gdb 觀察的一個結果.

1. 啓動GDB

gdb main

2. break 在 76行

(gdb) b 76

3. 執行程式

(gdb) r

4. 觀察變數的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(gdb) r
Starting program: /home/sheldon/programming/c_language/mutex_interface/main
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Sheldon Debug:[create_locker][64]Start

Breakpoint 1, create_locker () at main.c:76
76 return locker_thiz;
(gdb) p locker_thiz->lock_info
$1 = 0x603028 ""
(gdb) p &locker_thiz->lock_info
$2 = (char (*)[]) 0x603028
(gdb) p *(locker_thiz->lock_info)
$3 = 0 '\000'
(gdb) p pp_info->mutex_id
$4 = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 0, __spins = 0, __elision = 0, __list = {__prev = 0x0, __next = 0x0}},
__size = '\000' <repeats 39 times>, __align = 0}
(gdb) p &pp_info->mutex_id
$5 = (pthread_mutex_t *) 0x603028

locker_thiz->lock_info 其實就是會等於 locker_thiz+sizeof(Locker)

[HTTP][ASP][POST][表單] 分析網頁原始碼

文章目錄
  1. Purpose
  2. Introudction
  3. 表單
  4. 如何用改變URL的方式, 來獲取各個表單的資訊.

Purpose

有一個好朋友,最近在研究如何自動的把股市資料抓下來, 以利後續的分析處理

他問了我一個問題, 要怎麼了解底下文章, 爲什麼這樣的URL就可以抓取想要個資料

抓取鉅亨網個股歷史行情

老實說,我不是做web應用的,XDDD,當下的反應是 "瓦阿哉". 所以爲了要保存一些顏面.

花了時間看了一下. 怎麼分析html....

Introudction

他的目的是要抓取網頁中表單的資料,

所以必須要知道HTTP如何處理表單的.

在開始之前, 你必須要知道如何檢視html的原始碼,

這部份,最容易了.

先來安裝個chrome. 然後找一個有表單的網頁

(按右鍵) -> (檢視網頁原始碼)

大功告成, Aha....

表單

html的標籤有許多種, 這裡的聯結作者很用心誒.

但是現在我們其實只是要focus 在表單上.

表單標籤的keyword 其實就是 form, 所以你只需要在原始碼中查詢form的關鍵字, 你就會發現表單的位置.

例如底下,

1
2
3
4
5
6
<form name="aspnetForm" method="post" action="/twstock/ps_historyprice/1101.htm" id="aspnetForm">
<div>
...
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE"
...
</form>

標籤大多都是成對的出現,所以你發現了form的開頭,就可以看到一個/form的結尾

從上面的資訊可以看出一些東西, 組成這個表單標籤的元素, 其實有許多種,

底下只是一個例子,

1. name="aspnetForm"

這個就是這個表單的名字

2. method="post"

當你按完查詢按鍵之後, 會利用post的方式將表單以及一些user自定的參數,帶給action這個程式, 一般講到post的時後,都會提到get這個方法, 我大概只有一個概念, 似乎post會比get還要安全,XDD 這種粗淺的認知. 有興趣的可以看一下,底下的差異介紹.

GET VS POST Method

3. action="/twstock/ps_historyprice/1101.htm"

如同上面所說,其實1101.htm應該就是web server上某一個程式, 當我們按完查詢以後, 會將一些資料(例如, 開始日期與結束日期) 送到action這裏. 去做相對應的處理. 例子, 其實就是將這其間內的資料從data base裏面撈出來 在顯示給user看.

如何用改變URL的方式, 來獲取各個表單的資訊.

在開始之前,應該有人,會有一些疑問,爲什麼網址不變,但是卻可以撈到不同的股市資料, 其實就是剛剛那個post的方式, 做到的.

有人會問,要怎麼知道,新的表單需要在URL上多加什麼爾外的資訊. 才能獲得呢.

其實很直觀,你觀察一下網頁上的表單,會需要什麼資訊,這個例子是用, (開始日期與結束日期),你就直接在原始碼中找尋(開始日期與結束日期)

多們直觀對吧 kerker

1
2
3
4
5
6
7
8
9
10
11
<form name="aspnetForm" method="post" action="/twstock/ps_historyprice/1101.htm" id="aspnetForm">
...
<span class="srchyear2" >
開始日期<input name="ctl00$ContentPlaceHolder1$startText" type="text" value="2015/02/28" maxlength="10" id="ctl00_ContentPlaceHolder1_startText" style="width:72px;" />
結束日期<input name="ctl00$ContentPlaceHolder1$endText" type="text" value="2015/03/28" maxlength="10" id="ctl00_ContentPlaceHolder1_endText" style="width:72px;" />
<input type="submit" name="ctl00$ContentPlaceHolder1$submitBut" value="查詢" id="ctl00_ContentPlaceHolder1_submitBut" class="butn btnga" />
<span style="float:right">
</span>
</span>
...
</form>

這樣就可以發現,在表單裏面,其實有一段標籤是描述(開始日期與結束日期),

跟剛剛一樣,假如要知道input這個標籤屬性在幹嗎,查閱一下 HELP-HTML-標籤

這邊稍爲帶一下,

  1. name : 代表input 的名字
  2. type : input 的屬性,text很明顯就是只文字.
  3. value : 這個input 是什麼值. 看起來就像是日期.

有了以上的簡單的認知,我們就可以透過key URL 的方式,來改變我們要搜尋的股市歷史資料

首先, 由於我們這個是要股市歷史資料,你觀察一下,他的歷史資料的首頁,

1
http://www.cnyes.com/twstock/ps_historyprice.aspx

聯結進去預設的各股,是臺G電2330, 假如是要查聯發科2454的話.

你只要將code=2454 帶入URL中即可.像是底下.

要注意一個地方,假如我需要帶參數在URL中時,你就必須多加一個"?"在網址的最後面. 然後緊接着參數code

1
http://www.cnyes.com/twstock/ps_historyprice.aspx?code=2454

看起來真的很容易對吧...

再來就是,假如我需要知道某個區間內的歷史資料要怎麼做呢.

其實很間單,就是在多加時間的參數下去,對吧. 時間參數所要用的name 其實就是網頁原始碼中的name(可以參考上一段所說)

  1. Name of 開始時間 : ctl00$ContentPlaceHolder1$startText
  2. Name of 結束時間 : ctl00$ContentPlaceHolder1$endText

要注意兩個地方

  1. 等於(=)後面,就是塞值進去,這個例子就是時間.
  2. 帶入的每個參數之間都要有"&"將每個參數做區隔. 底下例子其實,就是三個參數.
1
http://www.cnyes.com/twstock/ps_historyprice.aspx?code=2454&ctl00$ContentPlaceHolder1$startText=2014/01/01&ctl00$ContentPlaceHolder1$endText=2014/01/28