Linux 编程--三种常用的定时器
这节我们来探讨一下linux开发过程中常用的定时器,尤其在网络编程中被常常用到如heartbeat,断线重连等等。这里提供了三种定时器的方案,分别是链表形式的计时器,环型计时器,最小堆计时器。每个都有不同的作用和优势,可以结合实际项目选择或者改良。
链表计时器:
链表计时器是一个实现很简单的一种计时器,可以使用单链表或者双链表来实现,我这里有一个双链表实现的例子
/**
* timer list
*
*
*
*
*
*/
#ifndef LIST_TIMER_H
#define LIST_TIMER_H
#include <time.h> typedef struct util_time{
struct util_time * prev; // 双链表的前驱
struct util_time * next; //双链表后驱
//Client data point
void * cdata; //其他数据
//timeout value
time_t out_time; //定时时间
int persist; //是否是坚持定时
//if timeout callback
void (*timeout_callback)(void * data); //定时回调函数
}UTIL_TIME; struct list_timer; struct TimerOP
{
int (*add)(struct list_timer * lt, UTIL_TIME * ut);
int (*del)(struct list_timer * lt, UTIL_TIME ** ut);
int (*adjust)(struct list_timer * lt, UTIL_TIME * ut, time_t _time);
void (*_tick)(struct list_timer * lt);
}; //Timer list
//定时器链表头
typedef struct list_timer
{
struct TimerOP timer_op;
UTIL_TIME * head;
UTIL_TIME * tail;
}LIST_TIMER; //timer list operator, all function only handle list and free timer, not free clientdata
int add_timer(LIST_TIMER * lt, UTIL_TIME * ut);
int del_timer(LIST_TIMER * lt, UTIL_TIME **ut);
int adjust_timer(LIST_TIMER * lt, UTIL_TIME * ut, time_t _time);
void tick(LIST_TIMER * lt);
void init_List_Timer(LIST_TIMER * lt);
void destroy_list_Timer(LIST_TIMER * lt);
#endif
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include "list_timer.h" /**
* @brief init_List_Timer
* @param lt timer list
* initialize list timer, head and tail are NULL
* 初始化定时器
*/
void init_List_Timer(LIST_TIMER *lt)
{
lt->timer_op.add = add_timer;
lt->timer_op.del = del_timer;
lt->timer_op.adjust = adjust_timer;
lt->timer_op._tick = tick;
lt->head = NULL;
lt->tail = NULL;
} /**
* @brief add_timer
* @param lt
* @param ut
* @return
* 添加一个定时器 并跟定时器排序
*/
int add_timer(LIST_TIMER * lt, UTIL_TIME * ut)
{
if (lt && ut)
{
if (!lt->head && !lt->tail)
{
lt->head = ut;
lt->tail = ut;
ut->prev = NULL;
ut->next = NULL;
return ;
}
else if (lt->head && lt->tail)
{
UTIL_TIME * temp = lt->head;
UTIL_TIME * tempbak = NULL;
while(temp)
{
if((temp->out_time) > (ut->out_time))
{
if(lt->head == temp)
{
ut->next = temp;
temp->prev = ut;
lt->head = ut;
ut->prev = NULL;
return ;
}
}
tempbak = temp;
temp = temp->next;
}
tempbak->next = ut;
ut->prev = tempbak;
ut->next = NULL;
lt->tail = ut;
return ;
}
return ;
}
return ;
} /**
* @brief del_timer
* @param lt
* @param ut
* @return
* 由相应定时器的位置删除定时器
*/
int del_timer(LIST_TIMER * lt, UTIL_TIME **ut)
{
if(lt && ut && *ut)
{
if(lt->head)
{
UTIL_TIME *temp = *ut;
if((temp == lt->head) && (temp != lt->tail)) //头
{
lt->head = temp->next;
temp->next->prev = NULL;
}
else if((temp == lt->tail) && (temp != lt->head)) //尾
{
temp->prev->next = NULL;
lt->tail = temp->prev;
}
else if((temp == lt->tail) && (temp == lt->head)) //只有一个定时器
{
lt->head = NULL;
lt->tail = NULL;
}
else
{
temp->next->prev = temp->prev;
temp->prev->next = temp->next;
}
(*ut)->cdata = NULL;
(*ut)->next = NULL;
(*ut)->prev = NULL;
(*ut)->timeout_callback = NULL;
free(*ut);
*ut = NULL;
ut = NULL;
return ;
}
}
return ;
} /**
* @brief adjust_timer
* @param lt
* @param ut
* @param _time
* @return
* if a timer be deleted or addition time to a timer, adjust timer list
* 移除指针并插入
*/
int adjust_timer(LIST_TIMER * lt, UTIL_TIME * ut, time_t _time)
{
if(!lt || !ut){
return ;
}
ut->out_time = time(NULL) + _time;
if(!ut->prev && !ut->next)
{
return ; //only have single Node
}else if (ut->prev && !ut->next) {
ut->prev->next = NULL; //if ut is tail Node, remove it.
ut->prev = NULL;
}else if (!ut->prev && ut->next) {
lt->head = ut->next; //if ut is head Node
ut->next->prev = NULL;
ut->next = NULL;
ut->prev = NULL;
}else{
ut->next->prev = ut->prev; //ut is middle
ut->prev->next = ut->next;
ut->next = NULL;
ut->prev = NULL;
}
// Can be optimized , insert after this Node.
if(add_timer(lt, ut)) //reinsert it
{
return ;
}
return ;
} /**
* @brief tick
* @param lt
* Timer list tick, depend on callback function, adjust timer.
*/
void tick(LIST_TIMER * lt)
{
if(lt){
time_t now = time(NULL);
UTIL_TIME *temp = lt->head;
UTIL_TIME *tempbak = temp;
while(temp)
{
tempbak = temp;
temp = temp->next;
if(tempbak->out_time <= now) //检查时间
{
tempbak->timeout_callback(tempbak->cdata);
if(!(tempbak->persist))
del_timer(lt, &tempbak);
else{
//persist time 重新调整
adjust_timer(lt, tempbak, tempbak->persist);
}
}else{
break;
}
}
return;
}
return;
} /**
* @brief destroy_list_Timer
* @param lt
* destroy timer list
*/
void destroy_list_Timer(LIST_TIMER *lt)
{
if(!lt){
return;
}
UTIL_TIME * temp = lt->head;
UTIL_TIME * tempnext = NULL;
while(temp){
tempnext = temp->next;
temp->cdata = NULL;
temp->next = NULL;
temp->prev = NULL;
temp->timeout_callback = NULL;
free(temp);
temp = tempnext;
}
lt->head = NULL;
lt->tail = NULL;
}
测试用例
#include "list_timer.h"
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h> enum {CONNECTED, READ, WROTE, NORMAL}; typedef struct ClientData{
int fd;
char ipaddr[];
char * data;
//This client monitor status
int flags;
//Timer point, if ut is null that mean not included into timer list.
struct util_time * ut;
}CLIENTDATA;
LIST_TIMER lt; void doit(void * mydata)
{
CLIENTDATA * data = (CLIENTDATA *)mydata;
if(data){
switch(data->flags){
case CONNECTED:
fprintf(stderr, "don`t delete\n");
break;
case READ:
fprintf(stderr, "delete \n");
break;
case WROTE:
break;
case NORMAL:
break;
default:
break;
}
}
} int main()
{
init_List_Timer(<);
CLIENTDATA * cl1 = (CLIENTDATA *)malloc(sizeof(CLIENTDATA));
cl1->data = NULL;
cl1->fd = ;
cl1->flags = CONNECTED; CLIENTDATA * cl2 = (CLIENTDATA *)malloc(sizeof(CLIENTDATA));
cl2->data = NULL;
cl2->fd = ;
cl2->flags = READ; UTIL_TIME *ut2 = (UTIL_TIME *)malloc(sizeof(UTIL_TIME));
ut2->timeout_callback = doit;
ut2->cdata = cl2;
ut2->out_time = time(NULL) + ;
ut2->persist = ; UTIL_TIME *ut1 = (UTIL_TIME *)malloc(sizeof(UTIL_TIME));
ut1->timeout_callback = doit;
ut1->cdata = cl1;
ut1->out_time = time(NULL)+ ;
ut1->persist = ; add_timer(<, ut1);
add_timer(<, ut2);
while(){
tick(<);
usleep();
}
return ;
}
list_timer.c list_timer.h 其中list_main.c为测试实例。 其中的tick函数 可以放在一个死循环中,这样就实现了简单的定时,每个定时器按照事件间隔的从小到大的顺序并使用双链表进行组织,若定时器为persist的话就反复调整计时器,加上每次间隔时间并重新调整链表。在tick中比对头个计时器的时间如果小于目前时间就执行相应回调函数。
如在epoll模型的服务器中若要加入某个定时器,可以这样做
while()
{
tick(timer);
epoll_wait(); //此处得到定时器的最短计时, 即双链表表头定时间隔作为 阻塞时间。
//其他
for(;;)
{
} }
此种定时器的效率跟链表操作相同插入 删除都是logN,调整计时器在链表的位置花费较多的时间(去掉重新插入)。
环形定时器:
这种定时器就像钟表一样,如秒针一样一秒移动一次,当秒针移动到相应位置时,查看此位置是否有定时器,若有就不断的check时间。这里的某个指针位置的定时器可以以链表形式由圈数量从小到大排列。指针走到某个位置查看链表的圈数若为0则表示时间到了 否则将圈数减1等待下次调用。如图所示:
这里给出实例代码如下:
#ifndef ROUND_TIMER_H
#define ROUND_TIMER_H
#include <time.h> typedef struct aw_timer{
void *data;
struct aw_timer * prev;
struct aw_timer * next;
time_t expect;
//current slot number
int slotnumber;
//timer loop cercle number
int loopcercle;
//weather persist
int persist;
//if return 0 : mean don`t delete timer
//return 1 : delete timer.
void (*timeout_callback)(void * data);
}AW_TIMER; #define N 60
typedef struct wh_timers{
//time gap 1 sec or 1 min or 1 hour
int timegap;
//current slot point locetion
int curslotpoint;
//timer list point
AW_TIMER *slot[N];
}WH_TIMERS; void init_wh_timer(WH_TIMERS * wt, int timegap);
int add_wh_timer(WH_TIMERS * wt, AW_TIMER *at);
int del_wh_timer(WH_TIMERS * wt, AW_TIMER **at, int remove);
int adjust_wh_timer(WH_TIMERS * wt, AW_TIMER *at);
void wh_tick(WH_TIMERS * wt);
void destory_wh_timer(WH_TIMERS * wt); #endif
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include "round_timer.h" /**
* @brief insert_sort_timer
* @param aw_list
* @param at
* sort timer depend on loopcercle
* 按照圈数插入
*/
static void insert_sort_timer(AW_TIMER ** aw_list, AW_TIMER **at)
{
if(aw_list && at)
{
AW_TIMER * atr = *aw_list;
while(atr){
if(((*at)->loopcercle <= (atr->loopcercle)) && (!atr->prev)){
(*at)->next = atr;
atr->prev = *at;
(*at)->prev = NULL;
*aw_list = *at;
return;
}
else if(((*at)->loopcercle >= (atr->loopcercle)) && (!atr->next)) {
atr->next = *at;
(*at)->prev = atr;
(*at)->next = NULL;
return;
}
else if(((*at)->loopcercle <= (atr->loopcercle)) && atr->next && atr->prev){
(*at)->next = atr;
(*at)->prev = atr->prev;
atr->prev->next = *at;
atr->prev = *at;
return;
}
atr = atr->next;
}
}
} /**
* @brief init_wh_timer
* @param wt
* @param timegap
* Initialize wheel timers, timegap mean seconds one step.
* If timegap < 0 , timegap = 1
*/
void init_wh_timer(WH_TIMERS * wt, int timegap)
{
if(wt){
wt->curslotpoint = ;
wt->timegap = timegap ? timegap : ;
int i;
for(i = ; i < N; ++i){
wt->slot[i] = NULL;
}
}
} /**
* @brief add_wh_timer
* @param wt
* @param at
* @return
* add a timer into wheel timers
*/
int add_wh_timer(WH_TIMERS *wt, AW_TIMER *at)
{
if(wt && at){
if(at->expect){
//get timer loop cercles.
at->loopcercle = (at->expect) / ((wt->timegap) * N);
//get timer slot number in wheel
at->slotnumber = (wt->curslotpoint + ((at->expect) / (wt->timegap))) % N;
int index_t = at->slotnumber;
if(wt->slot[index_t])
{
//If this slot is not empty, insert it sortable.
insert_sort_timer(&(wt->slot[index_t]), &at);
}else{
wt->slot[index_t] = at;
at->prev = NULL;
at->next = NULL;
}
}
}
} /**
* @brief del_wh_timer
* @param wt
* @param at
* @param remove
* @return
* delete a timer, and the remove flag mean weather free it or not.
*/
int del_wh_timer(WH_TIMERS *wt, AW_TIMER **at, int remove)
{
if(wt && at){
if(*at){
if(!((*at)->prev)){
wt->slot[(*at)->slotnumber] = (*at)->next;
if((*at)->next)
(*at)->next->prev = NULL;
}
else if(!((*at)->next))
{
if((*at)->prev)
(*at)->prev->next = NULL;
else
wt->slot[(*at)->slotnumber] = NULL;
}else{
(*at)->prev->next = (*at)->next;
(*at)->next->prev = (*at)->prev;
(*at)->prev = NULL;
(*at)->next = NULL;
}
//是否真的移除
if(remove){
free(*at);
*at = NULL;
}
}
return ;
}
return ;
} /**
* @brief adjust_wh_timer
* @param wt
* @param at
* @return
* reset timer, fristly, will remove timer, then insert wheel again.
*/
int adjust_wh_timer(WH_TIMERS *wt, AW_TIMER *at)
{
//调整计时器
if(wt && at)
{
del_wh_timer(wt, &at, );
add_wh_timer(wt, at);
}
} /**
* @brief wh_tick
* @param wt
* point move step by step, if slot is not null, run timeout callback function.
* if loop cercle sum > 0, will skip it.
*/
void wh_tick(WH_TIMERS *wt)
{
if(wt)
{
wt->curslotpoint = (wt->curslotpoint + )%N;
if(wt->slot[wt->curslotpoint])
{
AW_TIMER * at = wt->slot[wt->curslotpoint];
AW_TIMER *attemp = at;
while(at)
{
attemp = at->next;
if( >= at->loopcercle){
//圈数为0 开始调用
at->timeout_callback(at->data);
if(at->persist)
{
adjust_wh_timer(wt, at);
}else{
del_wh_timer(wt, &at, );
}
}else{
//等待下次被调 并停止循环
(at->loopcercle)--;
break;
}
at = attemp;
}
}
alarm(wt->timegap);
}
} /**
* @brief destory_wh_timer
* @param wt
* free timer wheel.
*/
void destory_wh_timer(WH_TIMERS *wt)
{
int i;
for(i = ; i < N; ++i)
{
if(wt->slot[i]){
AW_TIMER * timer = wt->slot[i];
AW_TIMER * temptimer = timer;
while(timer)
{
temptimer = timer->next;
free(timer);
timer = NULL;
timer = temptimer;
}
temptimer = NULL;
wt->slot[i] = NULL;
}
}
}
#include "list_timer.h"
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h> enum {CONNECTED, READ, WROTE, NORMAL}; typedef struct ClientData{
int fd;
char ipaddr[];
char * data;
//This client monitor status
int flags;
//Timer point, if ut is null that mean not included into timer list.
struct util_time * ut;
}CLIENTDATA;
LIST_TIMER lt; void doit(void * mydata)
{
CLIENTDATA * data = (CLIENTDATA *)mydata;
if(data){
switch(data->flags){
case CONNECTED:
fprintf(stderr, "don`t delete\n");
break;
case READ:
fprintf(stderr, "delete \n");
break;
case WROTE:
break;
case NORMAL:
break;
default:
break;
}
}
} int main()
{
init_List_Timer(<);
CLIENTDATA * cl1 = (CLIENTDATA *)malloc(sizeof(CLIENTDATA));
cl1->data = NULL;
cl1->fd = ;
cl1->flags = CONNECTED; CLIENTDATA * cl2 = (CLIENTDATA *)malloc(sizeof(CLIENTDATA));
cl2->data = NULL;
cl2->fd = ;
cl2->flags = READ; UTIL_TIME *ut2 = (UTIL_TIME *)malloc(sizeof(UTIL_TIME));
ut2->timeout_callback = doit;
ut2->cdata = cl2;
ut2->out_time = time(NULL) + ;
ut2->persist = ; UTIL_TIME *ut1 = (UTIL_TIME *)malloc(sizeof(UTIL_TIME));
ut1->timeout_callback = doit;
ut1->cdata = cl1;
ut1->out_time = time(NULL)+ ;
ut1->persist = ; add_timer(<, ut1);
add_timer(<, ut2);
while(){
tick(<);
usleep();
}
return ;
}
我们可以看到在例子中 我用了定时信号来模拟一秒走一次,我们注意到这里信号可能会造成某些系统调用的中断 这里可以将它该为类似链表计时器中那样,在循环中得到俩次时间间隔 若大于等于1s就将秒针加1, 不过这样可能就不太准确了。可以将时间间隔设置的稍微大一些。
最小堆计时器:
最小堆计时器是比较常用的一种计时器,在libevent中可以看到它的使用。这种数据结构每次返回的是最小值时间间隔定时器。Libevent 事件循环(1) 这里可以简单看一下它的用法。当添加计时器时,就不断调整计时器在堆中的位置保证堆顶是一个最小计时。当计时器从堆中删除时就不断的向下不断找最小的计时器放在堆顶,至于最小堆的实现这里有一篇不错的文章分享给大家 : 二叉堆(一)之 图文解析 和 C语言的实现
我这里给出一个实例代码:
#include <time.h>
typedef struct
{
int persist; //是否坚持
time_t timeout; //timeout = 时间间隔 + 现在时间
time_t timegap; //时间间隔
void * data; //用户数据
}Timer;
typedef struct
{
Timer *timer;
size_t size;
size_t capacity;
}HeapTimer; //动态数组 最小堆 HeapTimer * initHeapTimer(size_t s);
void min_heap_push(HeapTimer * ht, Timer * _timer);
void min_heap_pop(HeapTimer * ht, Timer * _timer);
int check_had_timeout(HeapTimer *ht, time_t now);
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "heap_time.h"
//添加计时器后 需要不断上调二茶堆 保证堆顶最小
static void flow_up(HeapTimer *ht, Timer *_timer)
{
if (ht && _timer)
{
if (ht->size == )
{
return;
}
else if (ht->size == )
{
memcpy(&(ht->timer[ht->size]), _timer, sizeof(Timer));
_timer = NULL;
return;
}
int temp = ht->size;
while(temp)
{
//与父节点比较
if (ht->timer[temp/].timeout > (_timer->timeout))
{
ht->timer[temp].timeout = ht->timer[temp/].timeout;
ht->timer[temp].data = ht->timer[temp/].data;
ht->timer[temp].persist = ht->timer[temp/].persist;
ht->timer[temp].timegap = ht->timer[temp/].timegap;
}else{
break;
}
temp = temp/;
}
memcpy(&(ht->timer[temp]), _timer, sizeof(Timer));
_timer = NULL;
}
}
//删除堆顶不断调整
static void flow_down(HeapTimer *ht)
{
unsigned int start = ;
unsigned int end = ht->size;
unsigned int current = start;
unsigned int l = *current;
while(l <= end)
{
//当节点存在右孩子,比较左右两个孩子找到最小的一个
if (l < end && (ht->timer[l+].timeout < ht->timer[l].timeout))
{
l++;
}
//拿最后一个与上次比较最小的一个比较 如果比它小就停止将最后一个放到此位置
if (ht->timer[end].timeout < ht->timer[l].timeout)
{
break;
}
else{
//将最小的上浮继续比对
ht->timer[current].timeout = ht->timer[l].timeout;
ht->timer[current].data = ht->timer[l].data;
ht->timer[current].persist = ht->timer[l].persist;
ht->timer[current].timegap = ht->timer[l].timegap;
current = l;
l = *current;
}
}
ht->timer[current].timeout = ht->timer[end].timeout;
ht->timer[current].data = ht->timer[end].data;
ht->timer[current].persist = ht->timer[end].persist;
ht->timer[current].timegap = ht->timer[end].timegap;
} HeapTimer * initHeapTimer(size_t s)
{
if (s <= (size_t))
{
return NULL;
}
HeapTimer * ht = (HeapTimer *)malloc(sizeof(HeapTimer));
if (!ht)
{
return NULL;
}
ht->size = ;
ht->capacity = s+;
ht->timer = (Timer *)malloc(sizeof(Timer) * (s+));
if (ht->timer)
{
memset(ht->timer, , sizeof(Timer)*(s+));
return ht;
}
return NULL;
}
//插入一个定时器
void min_heap_push(HeapTimer * ht, Timer * _timer)
{
if (ht && _timer)
{
if (ht->size == ht->capacity)
{
size_t need = ht->size + (ht->size)/;
Timer *temp = (Timer *)malloc(sizeof(Timer)*(need));
if(temp){
memset(temp, , sizeof(Timer)*(need));
memcpy(temp, ht->timer, sizeof(ht->size));
ht->capacity = need;
free(ht->timer);
ht->timer = temp;
temp = NULL;
}
}
(ht->size)++;
flow_up(ht, _timer);
}
}
//删除一个定时器
void min_heap_pop(HeapTimer * ht, Timer * _timer)
{
if ( ht && ht->size)
{
memset(_timer, , sizeof(Timer));
memcpy(_timer, &(ht->timer[]), sizeof(Timer));
ht->timer[].timeout = ht->timer[ht->size].timeout;
ht->timer[].data = ht->timer[ht->size].data;
ht->timer[].persist = ht->timer[ht->size].persist;
ht->timer[].timegap = ht->timer[ht->size].timegap;
if (ht->size > )
{
flow_down(ht);
}
ht->timer[ht->size].timeout = ;
ht->timer[ht->size].data = NULL;
ht->timer[ht->size].persist = ;
ht->timer[ht->size].timegap = ;
(ht->size)--;
}
}
//检查是否超时
int check_had_timeout(HeapTimer *ht, time_t now)
{
if (ht)
{
if (ht->size > (size_t))
{
return (ht->timer[]).timeout < now;
}
}
return ;
}
//为测试使用
int main()
{
HeapTimer *timer = initHeapTimer();
Timer t1;
t1.timegap = ;
t1.timeout = time(NULL) + t1.timegap;
t1.persist = ;
Timer t2;
t2.timegap = ;
t2.timeout = time(NULL) + ;
t2.persist = ;
min_heap_push(timer, &t1);
min_heap_push(timer, &t2);
while()
{
if (check_had_timeout(timer, time(NULL))) //不断检查和调整
{
Timer temp;
min_heap_pop(timer, &temp); //
if (temp.persist)
{
temp.timeout = time(NULL) + temp.timegap;
min_heap_push(timer, &temp);
}
printf("timeout %u\n", timer->size);
}
usleep();
}
return ;
}
堆计时器的效率还是可以的,插入删除logN。目前在网络编程中 最小堆计时常用到。
总结:
综上所述这三种常用的计时器做了简单介绍,其中实例代码仍有许多改进之处,存在不足之处敬请见谅及反馈,可以在github上找到: https://github.com/BambooAce/MyEvent/tree/master/src比较这三种定时器,一般在网络编程中较推荐的是链表计时器和最小堆计时器,在最新的libevent中也同时提供了这两种计时器可供选择。在网络编程中不乏缺少心跳检测,当客户端数量十分庞大时,小根堆定时器的好处就很明显了。
Linux 编程--三种常用的定时器的更多相关文章
- Linux下的微秒级定时器: usleep, nanosleep, select, pselect
Linux下的微秒级定时器: usleep, nanosleep, select, pselect 标签: linuxnulldelaystructdate 2012-02-07 23:29 4979 ...
- 牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结 转载
基础篇:操作系统.计算机网络.设计模式 一:操作系统 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式.(一定要会 ...
- 【转】牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结
基础篇:操作系统.计算机网络.设计模式 一:操作系统 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式.(一定要会 ...
- 面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结
基础篇:操作系统.计算机网络.设计模式 一:操作系统 1. 进程的有哪几种状态,状态转换图,及导致转换的事件. 2. 进程与线程的区别. 3. 进程通信的几种方式. 4. 线程同步几种方式.(一定要会 ...
- 从裸机编程到嵌入式Linux编程思想的转变------分而治之:驱动和应用程序
笔者学习嵌入式Linux也有一段时间了,很奇怪的是很多书讲驱动编程方面的知识,也有很多书将ARM9方面的知识,但是从以前51形式的(对寄存器直接操作,初始化芯片的功能模块)编程方法,和思维模式,变换为 ...
- 【转】[IT综合面试]牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结
感谢IT面试群 S-北京-陈磊 的整理分享. 基础篇:操作系统.计算机网络.设计模式 提高篇:WIN32.MFC与Linux 算法篇:算法与数据结构 一:操作系 ...
- Linux 编程中的API函数和系统调用的关系【转】
转自:http://blog.chinaunix.net/uid-25968088-id-3426027.html 原文地址:Linux 编程中的API函数和系统调用的关系 作者:up哥小号 API: ...
- linux编程获取本机网络相关参数
getifaddrs()和struct ifaddrs的使用,获取本机IP 博客分类: Linux C编程 ifaddrs结构体定义如下: struct ifaddrs { struct ifad ...
- Linux编程简介
Linux编程可以分为Shell(如BASH.TCSH.GAWK.Perl.Tcl和Tk等)编程和高级语言(C语言,C++语言,java语言等)编程,Linux程序需要首先转化为低级机器语言即所谓的二 ...
随机推荐
- ios微信支付 v3
V2版本和V3版本存在很大的差异. 1. 从成功通过微信支付商户的资料审核返回的邮件开始: 你可以获得这些参数 appid,appSecret,partnerID, partnerKey(从平 ...
- C#设计模式之十一外观模式(Facade)【结构型】
一.引言 快12点半了,要开始今天的写作了.很快,转眼设计模式已经写了十个了,今天我们要讲[结构型]设计模式的第五个模式,该模式是[外观模式],英文名称是:Facade Pattern.我们先从名字上 ...
- 哈尔滨理工大学第六届程序设计团队 I-Team
/* 以前做过一个插队的题,这个类似从后往前操作 */ #include <iostream> #include <stdio.h> #include <algorith ...
- Android 开发笔记___SD卡基本操作__图片读取写入
package com.example.alimjan.hello_world.Utils; import android.graphics.Bitmap; import android.graphi ...
- Intellij导入子项目时,maven列表子项目灰色不可用---解决方法
导入子项目的module时,左侧project目录中有一个module图标右下角没有小蓝点,maven管理列表该module为灰色(表明未被管理),尝试几次后终于找到解决方案. 贴一张调好过后的图 第 ...
- 转:ef获取某个表中的部分字段值
我有个新闻表 id,title,body,createtime,author,click 使用ef4.1 仅仅读取 id,title,createtime 并显示在页面上. public static ...
- Python学习中的一些小例子
这篇文章包括用Python编写的斐波那契数列,三位数的水仙花数和百钱买百鸡的基础代码 斐波那契数列: ''' def hanshu(n): n_1 = 1 n_2 = 1 m = n sumn = 0 ...
- python线程池实现多线程
参考文献 http://www.open-open.com/news/view/1c0179b http://blog.jobbole.com/52060/ 按照这个博客,实现获取多台服务器的空间使用 ...
- java中处理json各种各样转换方法
JSON 即 JavaScript Object Natation,它是一种轻量级的数据交换格式,非常适合于服务器与 JavaScript 的交互.本文将快速讲解 JSON 格式,并通过代码示例演示如 ...
- oracle数据库创建表,序列及添加代码案例
create table cdpt( id number(6), name varchar2(30), constraint pk_id primary key(id) ); 更改数据库的“延迟段创建 ...