全球彩票平台_全球彩票注册平台|官网下载地址

热门关键词: 全球彩票平台,全球彩票注册平台,全球彩官网下载地址

学习笔记,memcached学习笔记

C 学习笔记(1)——数据类型占空间大小,学习笔记空间尺寸

boolean bool 1 byte  
character char 1 byte May be signed or unsigned
  wchar_t 1 byte  
  char16_t 2 bytes C 11 type
  char32_t 4 bytes C 11 type
integer short 2 bytes  
  int 2 bytes  
  long 4 bytes  
  long long 8 bytes C99/C 11 type
floating point float 4 bytes  
  double 8 bytes  
  long double 8 bytes

 

boolean bool 1 byte character char 1 byte May be signed or unsigned wchar_t 1 byte char16_t 2 byt...

stl中的空间配置器,stl空间配置器

 一般我们习于旧贯的c 内部存款和储蓄器配置如下

class Foo { ... };
Foo* pf = new Foo; 
delete pf; 

 这里的new实际上分为两有个别实行。首先是先用::operator new配置内部存款和储蓄器,然后试行Foo::Foo()构造对象内容。delete也同样,先运维Foo::~Foo()析构对象,再用::operator delete释放内部存款和储蓄器。在SGI STL中,这两片段各自在<stl_alloc.h>和<stl_construct.h>中。本文讲的正是<stl_alloc.h>中的传说。
  SGI STL大校配置器分为两级。第一流直接用malloc和free管理内部存款和储蓄器,第二级则应用内部存储器池避防止内部存款和储蓄器碎片。这两级都由simple_alloc包装起来以适合stl规范。如图

图片 1

首先级由于尚未用operator new,所以要协调完成new-handler机制。小编仿写的代码如下

 1 #ifndef _MALLOC_ALLOC_H_ 
 2 #define _MALLOC_ALLOC_H_ 
 3 
 4 //定义内存不足又没有定义相关处理函数时抛出的异常
 5 #ifndef THROW_OOM
 6 #    include <stdio.h>
 7 #    include <stdlib.h>
 8 #    define THROW_OOM fprintf(stderr, "out of memoryn"); exit(1)
 9 #endif
10 
11 #include<stdlib.h>
12 
13 namespace Chenstl{
14 
15 //第一级空间配置器,直接用mallloc分配内存
16 //当需要分配的空间大于MAX_BYTES时使用
17     class malloc_alloc{
18     private:
19         static void *oom_malloc(size_t);    //声明时可以只写类型啊。。现在才知道
20         static void *oom_realloc(void *,size_t);
21         static void (* malloc_oom_handler)();    //处理malloc时内存不足时的函数指针
22     public:
23         static void *allocate(size_t n);
24         static void decllocate(void *p);
25 
26         static void *realloc(void *p, size_t new_sz);
27         //当内存不足时,需要客户端设置handler
28         static void set_malloc_oom_handler(void(*f)());
29     };    
30 }
31 
32 #endif

 

图片 2 1 #include "malloc_alloc.h" 2 3 using namespace Chenstl; 4 void *malloc_alloc::allocate(size_t n) 5 { 6 void *result = malloc(n); 7 if (0 == result) result = oom_malloc(n); 8 return result; 9 } 10 11 void malloc_alloc::decllocate(void *p) 12 { 13 free(p); 14 } 15 16 void * malloc_alloc::realloc(void *p, size_t new_sz) 17 { 18 void *result = realloc(p, new_sz); 19 if (0 == result) result = oom_realloc(p, new_sz); 20 return result; 21 } 22 23 //当内存不足时,供给客户端设置handler 24 void malloc_alloc::set_malloc_oom_handler(void(*f)()) 25 { 26 malloc_oom_handler = f; 27 } 28 29 void(*malloc_alloc::malloc_oom_handler)() = 0; 30 31 void *malloc_alloc::oom_malloc(size_t n) 32 {//不断试图拿走内部存款和储蓄器 33 void *result; 34 for (;;) //听说那样比while(1)效果更优 35 { 36 if (0 == malloc_oom_handler) THROW_OOM; 37 (*malloc_oom_handler)(); 38 result = malloc(n); 39 if (result) return result; 40 } 41 } 42 43 void *malloc_alloc::oom_realloc(void *p, size_t n) 44 { 45 void *result; 46 for (;;) 47 { 48 if (0 == malloc_oom_handler) THROW_OOM; 49 (*malloc_oom_handler)(); 50 result = realloc(p, n); 51 if (result) return result; 52 } 53 } malloc_alloc.cpp

  纵然急需的区块当先128bytes则用第顶尖,不然用第二级的内部存款和储蓄器池管理。为了便于管理,配置器会自动将内存须求量上调到8的倍数(要求20bytes时,自动调节为24bytes)。用十七个freelist处理内部存款和储蓄器池,为节省空间,使用union

union obj {   //free-lists的节点构造 
   union obj *next;
   char client[1];  //使用者可见
  };

 获取内部存款和储蓄器时的代码及步骤如下

图片 3void *default_alloc::allocate(size_t n) { obj *result = 0; obj **my_free_list = 0; if (n > MAX_BYTES) return malloc_alloc::allocate(n); //搜索free lists中合适的四个 my_free_list = free_list FREELIST_INDEX(n); result = *my_free_list; if(0 == result) {//未有找到可用的freelist,从内部存款和储蓄器池里抽出空间 return refill(ROUND_UP(n)); } //调整freelist *my_free_list = result->next; return result; } View Code

 图片 4

  当free list中从未可用区块时,调用refill()为free list填充空间,新的半空中取自内部存储器池(由chunk_alloc()达成)。若是内部存款和储蓄器池相当不足,则malloc之,如若系统heap空间也非常不足,chunk_alloc()就招来还应该有空闲区块的free list并将其内部存款和储蓄器充公,若是如故非常不够就调用第一流配置器。第超级配置器有落实new-handler机制,内部存款和储蓄器相当不够会抛出非常。

 

图片 5#ifndef _DEFAULT_ALLOC_H #define _DEFAULT_ALLOC_H namespace Chenstl{ //使用内部存款和储蓄器池以减掉碎片 class default_alloc { private: enum { ALIGN = 8}; enum { MAX_BYTES = 128 }; enum { NFREELISTS = 16 }; //static const int ALIGN = 8; //static const int MAX_BYTES = 128; //static const int NFREELISTS = 16; //MAX_BYTES/ALIGN union obj { //free-lists的节点构造 union obj *next; char client[1]; }; //freelist static obj *free_list[NFREELISTS]; static char *start_free; //内部存储器池的开局地方 static char *end_free; //内部存款和储蓄器池的停歇地方 static size_t heap_size; private: //将bytes上调至8的倍数 static size_t ROUND_UP(size_t bytes) { return ((bytes ALIGN - 1) & ~(ALIGN - 1)); } //获取合适的区块在freelist中的地点 static size_t FREELIST_INDEX(size_t __bytes) { return (((__bytes) (size_t)ALIGN

  • 1) / (size_t)ALIGN - 1); } //重临三个轻重缓急为n的靶子,并大概到场大小为n的别的区块到free-list static void *refill(size_t n); //配置第一次全国代表大会块空间,可容纳nobjs个轻重缓急为size的区块 //倘若配置nobjs个区块有所不便,nobjs大概会骤降 static char *chunk_alloc(size_t size, int &nobjs); public: static void *allocate(size_t n); static void deallocate(void *p, size_t n); static void *realloc(void *p, size_t old_sz, size_t new_sz); }; } #endif default_alloc.h

 

图片 6#include "default_alloc.h" #include "malloc_alloc.h" using namespace Chenstl; default_alloc::obj *default_alloc::free_list[NFREELISTS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; char *default_alloc::start_free = 0; //内部存款和储蓄器池的开首地方 char *default_alloc::end_free = 0; //内部存款和储蓄器池的甘休地点 size_t default_alloc::heap_size = 0; void *default_alloc::allocate(size_t n) { obj *result = 0; obj **my_free_list = 0; if (n > MAX_BYTES) return malloc_alloc::allocate(n); //找出free lists中极其的二个 my_free_list = free_list FREELIST_INDEX(n); result = *my_free_list; if(0 == result) {//没有找到可用的freelist,从内存池里抽出空间 return refill(ROUND_UP(n)); } //调整freelist *my_free_list = result->next; return result; } void default_alloc::deallocate(void *p, size_t n) { } //再次回到贰个分寸为n的目的,并恐怕投入大小为n的任何区块到freelist //在ANSI c中,void *分化意实行加减操作,所以chunk用char * void *default_alloc::refill(size_t n) { int objs = 20; char *chunk = chunk_alloc(n, objs); obj *next, *current; obj *result; obj **my_free_list; if (1 == objs) //只收取八个区块 return chunk; my_free_list = free_list FREELIST_INDEX(n); result = (obj *)chunk; //这一块再次回到给顾客端 //将freellist指向分配的区域 *my_free_list = next = (obj *)chunk n; for (int i = 1;; i ) { current = next; next = (obj *)((char *)next n); //这里注意无法一直用next n if (i == objs - 1) { current->next = 0; break; } else current->next = next; } return result; } char *default_alloc::chunk_alloc(size_t size, int &nobjs) { char *result = 0; size_t total_bytes = size*nobjs; size_t bytes_left = end_free

  • start_free; //内存池剩余空间 if (bytes_left >= total_bytes) {//内部存储器池丰盛提供所需内部存款和储蓄器 result = start_free; start_free = total_bytes; return result; } else if (bytes_left >= size) {//内部存款和储蓄器池丰裕供应二个以上的区块 nobjs = bytes_left / size; total_bytes = nobjs * size; result = start_free; start_free = total_bytes; return result; } else {//内部存储器池一块区块也供应不断 size_t bytes_to_get = 2 * total_bytes ROUND_UP(heap_size >> 4);; if (bytes_left>0) {//将内部存款和储蓄器池的零头分配给方便的freelist obj **my_free_list = free_list FREELIST_INDEX(bytes_left); ((obj *)start_free)->next = *my_free_list; *my_free_list = (obj *)start_free; } start_free = (char *)malloc(bytes_to_get); if (!start_free) {//系统堆内部存储器不足,搜索还未利用的freelist obj *p = 0; obj **my_free_list = 0; for (int i = size; i < MAX_BYTES; i) { my_free_list = free_list FREELIST_INDEX(i); p = *my_free_list; if (0 != p) {//还会有未使用的freelist start_free = (char *)p; *my_free_list = p->next; end_free = start_free i; //递归调用,订正nobjs return chunk_alloc(size, nobjs); } } //没内部存款和储蓄器可用,寄希望于第拔尖的new-handler或抛出卓殊 end_free = 0; start_free = (char *)malloc_alloc::allocate(bytes_to_get); } heap_size = bytes_to_get; end_free = start_free bytes_to_get; return chunk_alloc(size, nobjs);//递归调用,更正nobjs } } default_alloc.cpp

 

一般大家习于旧贯的c 内部存款和储蓄器配置如下 class Foo { ... };Foo * pf = new Foo; delete pf; 这里的new实际上分为两部分举办。...

memcached学习笔记——连接模型,memcached学习笔记

  memcached是怎么吧?memcached是一个不错的、高品质的内部存款和储蓄器缓存工具。

  memcached具备以下的特点:

  • 研讨轻松:memcached的服务器客商端通讯并不使用复杂的MXL等格式,而是选取简易的基于文本的情商。
  • 基于libevent的事件管理:libevent是个程序库,他将Linux 的epoll、BSD类操作系统的kqueue等日子拍卖功效封装成统一的接口。memcached使用这一个libevent库,因而能在Linux、BSD、Solaris等操作系统上宣布其高质量。(libevent是怎么)
  • 嵌入内部存款和储蓄器存款和储蓄方式:为了进步品质,memcached中保留的数目都存款和储蓄在memcached内置的内部存款和储蓄器存储空间中。由于数量仅存在于内存中,由此重启memcached,重启操作系统会促成整个数码未有。别的,内容体积高达内定的值之后memcached回机关删除不适用的缓存。
  • Memcached不互通讯的布满式:memcached尽管是“布满式”缓存服务器,但服务器端并不曾布满式作用。各种memcached不会相互通讯以共享消息。他的遍布式重视是通过客商端完结的。

  本文重要教师memcached的连接模型,memcached由一条主线程(连接线程)监听连接,然后把成功的连天交给子线程(工作线程)管理读写操作。N条【运行memcached通过-t命令钦赐】子线程(职业线程)负担读写多少,一条子线程(工作线程)维护着八个接二连三。三个conn结构体对象对应着叁个三回九转,主线程(连接线程)成功总是后,会把连接的内容赋值到多个conn结构体对象,并把那几个conn结构体对象传递给一条子线程(职业线程)管理。

图片 7

 

conn结构体:

图片 8 1 typedef struct conn conn; 2 struct conn { 3 int sfd; 4 sasl_conn_t *sasl_conn; 5 6 // 连接意况 7 enum conn_states state; 8 enum bin_substates substate; 9 struct event event; 10 short ev_flags; 11 12 // 刚刚出发的事件 13 short which; /** which events were just triggered */ 14 15 // read buffer 16 char *rbuf; /** buffer to read commands into */ 17 18 // 已经深入分析了一局地的命令, 指向业已解析甘休的地点 19 char *rcurr; /** but if we parsed some already, this is where we stopped */ 20 21 // rbuf 已分配的大小 22 int rsize; /** total allocated size of rbuf */ 23 24 // 尚未分析的指令大小 25 int rbytes; /** how much data, starting from rcur, do we have unparsed */ 26 27 // buffer to write 28 char *wbuf; 29 30 // 指向已经回来的地方 31 char *wcurr; 32 33 // 写大小 34 int wsize; 35 36 // 尚未写的数额大小 37 int wbytes; 38 39 /** which state to go into after finishing current write */ 40 // 当写回得了后供给霎时调换的意况 41 enum conn_states write_and_go; 42 43 void *write_and_free; /** free this memory after finishing writing */ 44 45 char *ritem; /** when we read in an item's value, it goes here */ 46 int rlbytes; 47 48 /* data for the nread state */ 49 50 /** 51 * item is used to hold an item structure created after reading the command 52 * line of set/add/replace commands, but before we finished reading the actual 53 * data. The data is read into ITEM_data(item) to avoid extra copying. 54 */ 55 56 // 指向当下亟需形成的任务 57 void *item; /* for commands set/add/replace */ 58 59 /* data for the swallow state */ 60 int sbytes; /* how many bytes to swallow */ 61 62 /* data for the mwrite state */ 63 struct iovec *iov; 64 int iovsize; /* number of elements allocated in iov[] */ 65 int iovused; /* number of elements used in iov[] */ 66 67 // msghdr 链表, 三个再而三只怕有五个 msghdr 68 // 若是是 UDP, 需求为每一个msghdr 填写一个 UDP 底部 69 struct msghdr *msglist; 70 int msgsize; /* number of elements allocated in msglist[] */ 71 int msgused; /* number of elements used in msglist[] */ 72 int msgcurr; /* element in msglist[] being transmitted now */ 73 int msgbytes; /* number of bytes in current msg */ 74 75 item **ilist; /* list of items to write out */ 76 int isize; 77 item **icurr; 78 79 // 记录职责数量 80 int ileft; 81 82 char **suffixlist; 83 int suffixsize; 84 char **suffixcurr; 85 int suffixleft; 86 87 enum protocol protocol; /* which protocol this connection speaks */ 88 enum network_transport transport; /* what transport is used by this connection */ 89 90 /* data for UDP clients */ 91 int request_id; /* Incoming UDP request ID, if this is a UDP "connection" */ 92 struct sockaddr request_addr; /* Who sent the most recent request */ 93 socklen_t request_addr_size; 94 95 unsigned char *hdrbuf; /* udp packet headers */ 96 int hdrsize; /* number of headers' worth of space is allocated */ 97 98 bool noreply; /* True if the reply should not be sent. */ 99 /* current stats command */ 100 struct { 101 char *buffer; 102 size_t size; 103 size_t offset; 104 } stats; 105 106 /* Binary protocol stuff */ 107 /* This is where the binary header goes */ 108 protocol_binary_request_header binary_header; 109 uint64_t cas; /* the cas to return */ 110 short cmd; /* current command being processed */ 111 112 // ? 不透明 113 int opaque; 114 int keylen; 115 116 // 可见是贰个链表 117 conn *next; /* Used for generating a list of conn structures */ 118 119 // 对准服务于此连接的线程 120 LIBEVENT_THREAD *thread; /* Pointer to the thread object serving this connection */ 121 }; View Code

  1 //memcached.c
  2 int main{
  3 
  4     // ......
  5 
  6     // 第一步:初始化主线程的事件机制
  7     /* initialize main thread libevent instance */
  8     // libevent 事件机制初始化
  9     main_base = event_init();
 10 
 11     // ......
 12 
 13     // 第二步:初始化 N 个 (初始值200,当连接超过200个的时候会往上递增) conn结构体对象
 14     // 空闲连接数组初始化
 15     conn_init();
 16 
 17     // ......
 18 
 19     
 20     // 第三步:启动工作线程
 21     /* start up worker threads if MT mode */
 22     thread_init(settings.num_threads, main_base);
 23     
 24     // ......
 25     
 26     // 第四步:初始化socket,绑定监听端口,为主线程的事件机制设置连接监听事件(event_set、event_add)
 27     /**
 28         memcached 有可配置的两种模式: unix 域套接字和 TCP/UDP, 允许客户端以两种方式向 memcached 发起请求. 客户端和服务器在同一个主机上的情况下可以用 unix 域套接字, 否则可以采用 TCP/UDP 的模式. 两种模式是不兼容的.
 29         以下的代码便是根据 settings.socketpath 的值来决定启用哪种方式.
 30     */
 31     /**
 32         第一种, unix 域套接字.
 33     */
 34     /* create unix mode sockets after dropping privileges */
 35     if (settings.socketpath != NULL) {
 36         errno = 0;
 37         if (server_socket_unix(settings.socketpath,settings.access)) {
 38             vperror("failed to listen on UNIX socket: %s", settings.socketpath);
 39             exit(EX_OSERR);
 40         }
 41     }
 42 
 43     /**
 44         第二种, TCP/UDP.
 45     */
 46     /* create the listening socket, bind it, and init */
 47     if (settings.socketpath == NULL) {
 48         const char *portnumber_filename = getenv("MEMCACHED_PORT_FILENAME");
 49         char temp_portnumber_filename[PATH_MAX];
 50         FILE *portnumber_file = NULL;
 51 
 52         // 读取端口号文件
 53         if (portnumber_filename != NULL) {
 54             snprintf(temp_portnumber_filename,
 55                      sizeof(temp_portnumber_filename),
 56                      "%s.lck", portnumber_filename);
 57 
 58             portnumber_file = fopen(temp_portnumber_filename, "a");
 59             if (portnumber_file == NULL) {
 60                 fprintf(stderr, "Failed to open "%s": %sn",
 61                         temp_portnumber_filename, strerror(errno));
 62             }
 63         }
 64 
 65         // TCP
 66         errno = 0;
 67         if (settings.port && server_sockets(settings.port, tcp_transport,
 68                                            portnumber_file)) {
 69             vperror("failed to listen on TCP port %d", settings.port);
 70             exit(EX_OSERR);
 71         }
 72 
 73         /*
 74          * initialization order: first create the listening sockets
 75          * (may need root on low ports), then drop root if needed,
 76          * then daemonise if needed, then init libevent (in some cases
 77          * descriptors created by libevent wouldn't survive forking).
 78          */
 79 
 80         // UDP
 81         /* create the UDP listening socket and bind it */
 82         errno = 0;
 83         if (settings.udpport && server_sockets(settings.udpport, udp_transport,
 84                                               portnumber_file)) {
 85             vperror("failed to listen on UDP port %d", settings.udpport);
 86             exit(EX_OSERR);
 87         }
 88 
 89         if (portnumber_file) {
 90             fclose(portnumber_file);
 91             rename(temp_portnumber_filename, portnumber_filename);
 92         }
 93     }
 94 
 95     // ......
 96     
 97     
 98     // 第五步:主线程进入事件循环
 99     /* enter the event loop */
100     // 进入事件循环
101     if (event_base_loop(main_base, 0) != 0) {
102         retval = EXIT_FAILURE;
103     }
104 
105     // ......
106 
107 }

  LIBEVENT_THREAD 结构体:

图片 9 1 // 八个线程, 每一种线程一个 event_base 2 typedef struct { 3 pthread_t thread_id; /* unique ID of this thread */ 4 struct event_base *base; /* libevent handle this thread uses */ 5 6 // event 结构体, 用于管道读写事件的监听 7 struct event notify_event; /* listen event for notify pipe */ 8 9 // 读写管道文件汇报符 10 int notify_receive_fd; /* receiving end of notify pipe */ 11 int notify_send_fd; /* sending end of notify pipe */ 12 13 // 线程的景色14 struct thread_stats stats; /* Stats generated by this thread */ 15 16 // 那些线程需求管理的连接队列 17 struct conn_queue *new_conn_queue; /* queue of new connections to handle */ 18 cache_t *suffix_cache; /* suffix cache */ 19 uint8_t item_lock_type; /* use fine-grained or global item lock */ 20 } LIBEVENT_THREAD; View Code

  第三步职业线程的详细运营进程:

  1 /*
  2  * thread.c
  3  *
  4  * 初始化线程子系统, 创建工作线程
  5  * Initializes the thread subsystem, creating various worker threads.
  6  *
  7  * nthreads  Number of worker event handler threads to spawn
  8  *   需准备的线程数
  9  * main_base Event base for main thread
 10  *   分发线程
 11  */
 12 void thread_init(int nthreads, struct event_base *main_base) {
 13     int         i;
 14     int         power;
 15 
 16     // 互斥量初始化
 17     pthread_mutex_init(&cache_lock, NULL);
 18     pthread_mutex_init(&stats_lock, NULL);
 19 
 20     pthread_mutex_init(&init_lock, NULL);
 21     //条件同步
 22     pthread_cond_init(&init_cond, NULL);
 23 
 24     pthread_mutex_init(&cqi_freelist_lock, NULL);
 25     cqi_freelist = NULL;
 26 
 27     /* Want a wide lock table, but don't waste memory */
 28     if (nthreads < 3) {
 29         power = 10;
 30     } else if (nthreads < 4) {
 31         power = 11;
 32     } else if (nthreads < 5) {
 33         power = 12;
 34     } else {
 35         // 2^13
 36         /* 8192 buckets, and central locks don't scale much past 5 threads */
 37         power = 13;
 38     }
 39 
 40     // hashsize = 2^n
 41     item_lock_count = hashsize(power);
 42 
 43     item_locks = calloc(item_lock_count, sizeof(pthread_mutex_t));
 44     if (! item_locks) {
 45         perror("Can't allocate item locks");
 46         exit(1);
 47     }
 48     // 初始化
 49     for (i = 0; i < item_lock_count; i  ) {
 50         pthread_mutex_init(&item_locks[i], NULL);
 51     }
 52     //item_lock_type_key设置为线程的私有变量的key
 53     pthread_key_create(&item_lock_type_key, NULL);
 54     pthread_mutex_init(&item_global_lock, NULL);
 55 
 56 
 57     // LIBEVENT_THREAD 是结合 libevent 使用的结构体, event_base, 读写管道
 58     threads = calloc(nthreads, sizeof(LIBEVENT_THREAD));
 59     if (! threads) {
 60         perror("Can't allocate thread descriptors");
 61         exit(1);
 62     }
 63 
 64     // main_base 是分发任务的线程, 即主线程
 65     dispatcher_thread.base = main_base;
 66     dispatcher_thread.thread_id = pthread_self();
 67 
 68     // 管道, libevent 通知用的
 69     // 一个 LIBEVENT_THREAD 结构体对象对应由一条子线程维护
 70     // 子线程通过读管道来接收主线程的命令(例如主线程接收到新连接,会往子线程的读管道写入字符'c',子线程接收到命令就会做出相应的处理)
 71     for (i = 0; i < nthreads; i  ) {
 72         int fds[2];
 73         if (pipe(fds)) {
 74             perror("Can't create notify pipe");
 75             exit(1);
 76         }
 77 
 78         // 读管道
 79         threads[i].notify_receive_fd = fds[0];
 80         // 写管道
 81         threads[i].notify_send_fd = fds[1];
 82 
 83         // 初始化线程信息数据结构, 其中就将 event 结构体的回调函数设置为 thread_libevent_process(),此时线程还没有创建
 84         setup_thread(&threads[i]);
 85         /* Reserve three fds for the libevent base, and two for the pipe */
 86         stats.reserved_fds  = 5;
 87     }
 88 
 89     /* Create threads after we've done all the libevent setup. */
 90     // 创建并初始化线程, 线程的代码都是 work_libevent()
 91     for (i = 0; i < nthreads; i  ) {
 92         // 调用 pthread_attr_init() 和 pthread_create() 来创建子线程
 93         // 子线程的函数入口 worker_libevent ,负责启动子线程的事件循环
 94         create_worker(worker_libevent, &threads[i]);
 95     }
 96 
 97     /* Wait for all the threads to set themselves up before returning. */
 98     pthread_mutex_lock(&init_lock);
 99     // wait_for_thread_registration() 是 pthread_cond_wait 的调用
100     wait_for_thread_registration(nthreads);
101     pthread_mutex_unlock(&init_lock);
102 }
103 
104 
105 
106 
107 /*
108  * Set up a thread's information.
109  */
110  // 填充 LIBEVENT_THREAD 结构体, 其中包括:
111  //     填充 struct event
112  //     初始化线程工作队列
113  //     初始化互斥量
114  //     等
115 static void setup_thread(LIBEVENT_THREAD *me) {
116     // 子线程的事件机制,每条子线程都有一个事件机制
117     me->base = event_init();
118     if (! me->base) {
119         fprintf(stderr, "Can't allocate event basen");
120         exit(1);
121     }
122 
123     /* Listen for notifications from other threads */
124     // 在线程数据结构初始化的时候, 为 me->notify_receive_fd 读管道注册读事件, 回调函数是 thread_libevent_process()
125     // 为子线程的事件机制添加事件
126     event_set(&me->notify_event, me->notify_receive_fd,
127               EV_READ | EV_PERSIST, thread_libevent_process, me);
128     event_base_set(me->base, &me->notify_event);
129 
130     if (event_add(&me->notify_event, 0) == -1) {
131         fprintf(stderr, "Can't monitor libevent notify pipen");
132         exit(1);
133     }
134     
135     // ......
136 }
137 
138 
139 
140 /*
141  * Worker thread: main event loop
142  * 线程函数入口, 启动事件循环
143  */
144 static void *worker_libevent(void *arg) {
145     LIBEVENT_THREAD *me = arg;
146 
147     // ......
148     
149     // 进入事件循环
150     event_base_loop(me->base, 0);
151     return NULL;
152 }

  子线程读管道回调函数:

图片 10 1 /* 2 * Processes an incoming "handle a new connection" item. This is called when 3 * input arrives on the libevent wakeup pipe. 4 * 5 * 当管道有数据可读的时候会触发此函数的调用 6 */ 7 static void thread_libevent_process(int fd, short which, void *arg) { 8 LIBEVENT_THREAD *me = arg; 9 CQ_ITEM *item; 10 char buf[1]; 11 12 if (read(fd, buf, 1) != 1) 13 if (settings.verbose > 0) 14 fprintf(stderr, "Can't read from libevent pipen"); 15 16 switch (buf[0]) { 17 case 'c': 18 // 表示主线程把三个新的总是分发给该子线程管理 19 // 抽出一个职分 20 item = cq_pop(me->new_conn_queue); 21 22 if (NULL != item) { 23 // 为新的乞求创设三个连接结构体. 连接其实早已确立, 这里只是为了填充连接结构体. 最要紧的动作是在 libevent 中登记了风浪, 回调函数是 event_handler() 24 conn *c = conn_new(item->sfd, item->init_state, item->event_flags, 25 item->read_buffer_size, item->transport, me->base); 26 if (c == NULL) { 27 if (IS_UDP(item->transport)) { 28 fprintf(stderr, "Can't listen for events on UDP socketn"); 29 exit(1); 30 } else { 31 if (settings.verbose > 0) { 32 fprintf(stderr, "Can't listen for events on fd %dn", 33 item->sfd); 34 } 35 close(item->sfd); 36 } 37 } else { 38 c->thread = me; 39 } 40 cqi_free(item); 41 } 42 break; 43 44 /* we were told to flip the lock type and report in */ 45 case 'l': 46 me->item_lock_type = ITEM_LOCK_GRANULAR; 47 register_thread_initialized(); 48 break; 49 50 case 'g': 51 me->item_lock_type = ITEM_LOCK_GLOBAL; 52 register_thread_initialized(); 53 break; 54 } 55 } View Code

 

  第四步关键是初叶化socket、绑定服务器端口和IP、为主线程事件机制增多监听连接事件:

  1 // memcached.c
  2 // server_sockets()->server_socket()
  3 
  4 static int server_socket(const char *interface,
  5                          int port,
  6                          enum network_transport transport,
  7                          FILE *portnumber_file) {
  8                          
  9     // ......
 10 
 11     // getaddrinfo函数能够处理名字到地址以及服务到端口这两种转换,返回的是一个addrinfo的结构(列表)指针而不是一个地址清单。
 12     error= getaddrinfo(interface, port_buf, &hints, &ai);
 13 
 14     if (error != 0) {
 15         if (error != EAI_SYSTEM)
 16           fprintf(stderr, "getaddrinfo(): %sn", gai_strerror(error));
 17         else
 18           perror("getaddrinfo()");
 19         return 1;
 20     }
 21 
 22     for (next= ai; next; next= next->ai_next) {
 23         conn *listen_conn_add;
 24 
 25         // new_socket() 申请了一个 UNIX 域套接字,通过调用socket()方法创建套接字,并设置把套接字为非阻塞
 26         if ((sfd = new_socket(next)) == -1) {
 27             
 28             // ......
 29             
 30         }// if
 31 
 32         
 33         // ......
 34         
 35 
 36         // bind() 绑定源IP的端口
 37         if (bind(sfd, next->ai_addr, next->ai_addrlen) == -1) {
 38             
 39             // ......
 40             
 41         } else {
 42             success  ;
 43             // bind()调用成功后,调用listen()
 44             if (!IS_UDP(transport) && listen(sfd, settings.backlog) == -1) {
 45                 
 46                 // ......
 47                 
 48             }
 49             
 50             // ......
 51             
 52         }
 53 
 54         // UDP 和 TCP 区分对待, UDP 没有连接概念, 只要绑定服务器之后, 直接读取 socket 就好了, 所以与它对应 conn 的初始状态应该为 conn_read; 而 TCP 对应的 conn 初始状态应该为 conn_listening
 55         if (IS_UDP(transport)) {
 56             // UDP
 57             int c;
 58 
 59             for (c = 0; c < settings.num_threads_per_udp; c  ) {
 60                 /* this is guaranteed to hit all threads because we round-robin */
 61                 // 分发新的连接到线程池中的一个线程中
 62                 dispatch_conn_new(sfd, conn_read, EV_READ | EV_PERSIST,
 63                                   UDP_READ_BUFFER_SIZE, transport);
 64             }
 65         } else {
 66             // TCP 要建立连接
 67             if (!(listen_conn_add = conn_new(sfd, conn_listening,
 68                                              EV_READ | EV_PERSIST, 1,
 69                                              transport, main_base))) {
 70                 fprintf(stderr, "failed to create listening connectionn");
 71                 exit(EXIT_FAILURE);
 72             }
 73 
 74             // 放在头部, listen_conn 是头指针
 75             listen_conn_add->next = listen_conn;
 76             listen_conn = listen_conn_add;
 77         }
 78     }
 79 
 80     freeaddrinfo(ai);
 81 
 82     /* Return zero iff we detected no errors in starting up connections */
 83     return success == 0;
 84 }
 85 
 86 
 87 
 88 
 89 // 填写 struct conn 结构体, 包括 struct conn 中的 event 结构, 并返回
 90 conn *conn_new(const int sfd, enum conn_states init_state,
 91                 const int event_flags,
 92                 const int read_buffer_size, enum network_transport transport,
 93                 struct event_base *base) {
 94     // c 指向一个新的 conn 空间
 95     // 可能是出于性能的考虑, memcached 预分配了若干个 struct conn 空间
 96     {
 97         /* data */
 98     };
 99     conn *c = conn_from_freelist();
100 
101     if (NULL == c) {
102         // 可能分配失败了, 因为默认数量有限. 进行新的扩展,conn_init()中初始数量是200
103         if (!(c = (conn *)calloc(1, sizeof(conn)))) {
104             fprintf(stderr, "calloc()n");
105             return NULL;
106         }
107 
108         // ......
109         // 填充conn结构体
110         
111     }// if
112 
113     
114     // ......
115     
116     
117     // libevent 操作: 设置事件, 设置回调函数 event_handler()
118     event_set(&c->event, sfd, event_flags, event_handler, (void *)c);
119 
120     // libevent 操作:设置 c->event 的 event_base
121     event_base_set(base, &c->event);
122 
123     c->ev_flags = event_flags;
124 
125     // libevent 操作: 添加事件
126     if (event_add(&c->event, 0) == -1) {
127 
128         // ......
129         
130     }
131 
132     
133     // ......
134     
135 
136     return c;
137 }

 

 

 

  

Java IO学习笔记(三)转变流、数据流、字节数组流,io学习笔记

转换流

1、转变流:将字节流转变来字符流,转换之后就足以二个字符多个字符的往程序写内容了,并且能够调用字符节点流的write(String s)方法,还足以在外围套用BufferedReader()和BufferedWriter,并运用它们的readLine 和 newLine方法。 2、有二种调换流:InputStreamReader、OutputStreamWriter   练习小程序1: package test.io.transfer; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; public class OutputStreamWriterTest {      public static void main(String args[]){            FileOutputStream fos = null;            FileOutputStream fos1 = null;            OutputStreamWriter opsw = null;            try {                 fos = new FileOutputStream("E:/技巧学习/java/test/Socket/test4.txt");                 fos1 = new FileOutputStream("E:/技艺学习/java/test/Socket/test5.txt");                 opsw = new OutputStreamWriter(fos);                 opsw.write("调换流演习");                 System.out.println(opsw.getEncoding());//获取编码格式                 opsw.flush();                 opsw.close();                 opsw = new OutputStreamWriter(fos1,"GBK");                 opsw.write("转换流练习转变流演习");                 System.out.println(opsw.getEncoding());//获取编码格式                 opsw.flush();            } catch (IOException e) {                 e.printStackTrace();            }finally{                 try {                      fos.close();                      opsw.close();                 } catch (IOException e) {                      e.printStackTrace();                 }            }      } }   演习小程序2: package test.io.transfer; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class InputStreamReaderTest {      public static void main(String args[]){            InputStreamReader isr = new InputStreamReader(System.in);//System.in是inputstream的子类            BufferedReader bf = new BufferedReader(isr);            String ss = null;            try {                 while((ss=bf.readLine()) != null){                      if(ss.equals("exit")){                            break;                      }                      System.out.println(ss);                 }            } catch (IOException e) {                 e.printStackTrace();            }finally{                 try {                      isr.close();                      bf.close();                 } catch (IOException e) {                      e.printStackTrace();                 }            }      } }   数据流、字节数组流 1、数据流:一般的字节流只好读写byte[]类其余数量,只可以写int、byte、byte[]类型的数据 ;字符输入流只好读char[]花色的多寡,字符输出流只好写char、char[]、int、String类型的多少。借使想要读写long、double、boolean等任何项目的多寡,就需求用到数据流。 2、数据流是一种管理流,有二种数据流:DataInputStream、DataOutputStream,分别承接于InputStream和OutputStream。他们须求套在InputStream和OutputStream类型的字节流上操作,下图中截取一些,具体方法见协助文档。   DataInputStream: 图片 11

 

DataOutputStream:

图片 12

 

  DataInputStream的构造方法:DataInputStream(InputStream in) DataOutputStream 的构造方法:DataOutputStream(OutputStream out) 3、字节数组流(字节流): ByteArrayInputStream: 字节数组输入流在内部存款和储蓄器中开创八个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中,从字节数组中读数据。 ByteArrayOutputStream:创建字节数组输出流的还要,内部存款和储蓄器会为该输出流创制一个暗中同意大小的字节数组,用于存款和储蓄写入的字节内容。 4、字节数组流的构造方法: ByteArrayInputStream(byte[] buf); ByteArrayInputStream(byte[] buf, int offset, int length); ByteArrayOutputStream(); 创制字节输出流的还要内部存款和储蓄器中会创立二个byte[]字节数组,暗中认可大小。 ByteArrayOutputStream(int size); 成立字节输出流的同有的时候间内部存款和储蓄器中会创设一个分寸为size的byte[]字节数组。 在动用的时候,能够用byte[] b = byteArrayOutputStream.toByteArray()重临流中的字节数组,然后创造ByteArrayInputStream bai = new ByteArrayInputStream(byte[] b)来将输入流接入到字节数组上。   演练小例子: package test.io.data; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; public class DataByteArrayStreamTest {      public static void main(String args[]){            ByteArrayOutputStream baos = new ByteArrayOutputStream();            DataOutputStream dos = new DataOutputStream(baos);            ByteArrayInputStream bais = null;            DataInputStream dis = null;            try {                 dos.writeDouble(Math.random());                 dos.writeBoolean(true);                 dos.flush();                 bais = new ByteArrayInputStream(baos.toByteArray());                 dis = new DataInputStream(bais);                 System.out.println(dis.available());                 //先进先出,先写先读,假使这里是先读的Boolean,则会自行找到存入的double数据的第一个字节,当做boolean类型读出来                 System.out.println(dis.readDouble());                 System.out.println(dis.readBoolean());            } catch (IOException e) {                 e.printStackTrace();            }finally{                 try {                      if(baos != null){                            baos.close();                      }                      if(dos != null){                            dos.close();                      }                      if(bais != null){                            bais.close();                      }                      if(dis != null){                            dis.close();                      }                 } catch (IOException e) {                      e.printStackTrace();                 }            }          } }   调节台出口结果: 9 0.02241410198642526 true

 

IO学习笔记(三)转变流、数据流、字节数组流,io学习笔记 调换流 1、调换流:将字节流调换到字符流,调换之后就足以贰个字符三个...

//---------------------------15/04/05----------------------------

java怎完成连接某一个memcached服务器

所谓的memcache驱动无非是提供了 与memcache socket连接和系列化的服从  

/*

linux系统中memcachedconnection连接意况改造怎办

在百度上问编制程序题!?假若C入门还也可能有人回答......
死心吧  

memcached是什么样呢?memcached是一个安然依然的、高质量的内部存款和储蓄器缓存工具。 memcached具备以下的特点...

    空间配置器概述:

    1:new操作包蕴八个品级操作

        1>调用::operator new配置内部存款和储蓄器(底层使用malloc来申请内部存款和储蓄器)。

        2>调用函数的构造函数,构造对象内容。

    delte和new同样,先调用析构函数,再调用::operator delete释放内存。

    2:为了作用,stl把八个阶段分别来。

        1>内部存款和储蓄器配置操作: alloc::allocate();

        2>内部存款和储蓄器释放操作: alloc::deallocate();

        3>对象协会操作: ::construct();

        4>对象析构操作: ::destory();

    3:内部存款和储蓄器配置器的完整:

        1><stl_construct.h>     : 这里定义了大局函数construct()和的destroy()。

        2><stl_alloc.h>         : 定义了一二级配置器。

        3><stl_uninitialized.h> : 定义了有的大局函数,用来填充或复制大块内部存款和储蓄器数据。

        un_initialized_copy(), un_initialized_fill(), un_initialized_fill_n()

        这几个函数对功能考虑得一帆风顺:最差的意况下会调用construct(),最棒的情况下会

        使用c的科班函数memmove()直接开展内部存款和储蓄器数据的活动。

 

*/

//construct() 和 destroy()

template<class T1, class T2>

inline void construct(T1* p, const T2& value)

{

    new (p) T1(value);

}

template<class T>

inline void destroy(T* pointer)

{

    pointer->~T();

}

template<class ForwardIterator>

inline void destroy(ForwardIterator first, ForwardIterator last)

{

    __destroy(first, last, value_type(first));

}

template<class ForwardIterator, class T>

inline void __destroy(ForwardIterator first, ForwardIterator last, T*)

{

    typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;

    __destroy_aux(first, last, trivial_destructor());

}

template<class ForwardIterator>

inline void

__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type)

{

    for(; first < last; first)

        destroy(&*first);

}

template<class ForwardIterator>

inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}

inline void destroy(char*, char*) {}

inline void destroy(wchar_t*, wchar_t*) {}

//alloc

template<class T, class Alloc>

class simple_alloc

{

public:

    static T* allocate(size_t n)

    {

        return 0 == n ? 0 : (T*) Alloc::allocate(n * sizeof(T));

    }

    

    static T* allocate(void)

    {

        return (T*) Alloc::allocate(sizeof(T));

    }

    

    static void deallocate(T *p, size_t n)

    {

        if(0 != n)

本文由全球彩票平台发布于全球彩票注册平台编程,转载请注明出处:学习笔记,memcached学习笔记

TAG标签: 全球彩票平台
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。