存档:c/c++

博客记忆

四月 23, 2010 | c/c++, js/web, linux, mysql, php, 心情杂记, 数学 | RSS 2.0

很长时间没有更新日志,大概有几个月了,疏于对知识的学习和管理,可能是跟工作有点忙有关系吧,经常顾着不顾那个,放弃了诸多的学习机会,
不过希望以后能恢复,时间是一种财富,能让你积淀更多的对知识的理解,同时也能验证更多的真理,譬如坚持才是硬道理,这两个月坚持的最好的一件事情还算是对自己花销的记录很分类,方法比较土,就是使用网易的邮箱里的一个小插件,有时候别人问你一个月能花多少钱?像我这种不扫一屋的人是一无所知的,统计了下发现对多的是花在了吃上和没周末的超市。
记得以前写博客都是从外面copy一堆东西,可能是自己的知识欠缺的太多,发现一篇技术文章就copy过来,沾沾自喜一番感觉很有成就感,后来发现好多牛人都是自己写博客,发现自己土了,而且写的都是超高技术含量,,而且现在基本上很多的知识获取都是从blog获得的,自己也曾在google reader里面follow了一堆,曾经每天早上9点到公司都花费10分钟时间,不过有点不好,开始没分类好,造成后来好多看的时候乱,杂乱无章的,挑出那种令你很满意的需要去甄选,所以有时候就懒的去看了。
不过一些东西一旦写下来还是能整理下自己的思维的。而且能做下备忘,所以以后需要把这个习惯坚持下去。今天写这个主要是想试试用vim写博客,用的是vimpress插件,下载地址在http://www.vim.org/scripts/script.php?script_id=1953,下来后直接解压到.vim下就可以了,修改blog.vim下的秘密用户还xmlrpc就可以了。ok,here,travel start。

没有评论 »

For , While 那个更快?

九月 5, 2009 | c/c++, 数据结构算法, 软件工程/编程技巧/设计模式 | RSS 2.0

到底是for快还是while快?有人做了一下测试:

for (;;) {
}

while (1) {
}

生成的汇编分别是:

for的是:

.text
.globl _main
_main:
pushl    %ebp
movl    %esp, %ebp
subl    $8, %esp
L2:
jmp    L2
.subsections_via_symbols

while的是:

.text
.globl _main
_main:
pushl    %ebp
movl    %esp, %ebp
subl    $8, %esp
L2:
jmp    L2
.subsections_via_symbols

现在你知道了吧

—————————————————http://blog.marcelotoledo.org/2008/10/22/for-or-while/


				

没有评论 »

取当前进程对应之静态映像文件的绝对路径/proc/self/exe

五月 22, 2009 | c/c++, linux | RSS 2.0

提供一个linux  advanced programming 上的得到绝对路径目录的函数:
char* get_self_executable_directory ()
{
  int rval;
  char link_target[1024];//目标地址
  char* last_slash;
  size_t result_length;//结果的长度
  char* result;

  /* Read the target of the symbolic link /proc/self/exe.  */
读取绝对路径
  rval = readlink (”/proc/self/exe”, link_target, sizeof (link_target) – 1);
  if (rval == -1)
    /* The call to readlink failed, so bail.  */
    abort ();
  else
    /* NUL-terminate the target.  */
    link_target[rval] = ‘0′;
  /* We want to trim the name of the executable file, to obtain the
     directory that contains it.  Find the rightmost slash.  */
找到最后一个/
  last_slash = strrchr (link_target, ‘/’);
如果是空或者是以/开头,则退出
  if (last_slash == NULL || last_slash == link_target)
    /* Something stange is going on.  */
    abort ();
last_slash保存的是最后的/的地址
  /* Allocate a buffer to hold the resulting path.  */
link_target开始的地址
  result_length = last_slash – link_target;
  result = (char*) xmalloc (result_length + 1);
  /* Copy the result.  */
  strncpy (result, link_target, result_length);
  result[result_length] = ‘0′;
  return result;
}

同时可以用以下程序得到绝对路径
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXBUFSIZE 1024

int main ( int argc, char * argv[] )
{
    char buf[ MAXBUFSIZE ];
    int  count;

    count = readlink( ”/proc/self/exe”, buf, MAXBUFSIZE );
    if ( count < 0 || count >= MAXBUFSIZE )
    {
        printf( ”Failed” );
       return( EXIT_FAILURE );
    }
    buf[ count ] = ’0′;
    printf( ”/proc/self/exe -> [%s]“, buf );
    return( EXIT_SUCCESS );

网站 :
1 http://www.smth.edu.cn/bbsanc.php?path=%2Fgroups%2Fos.faq%2FUnix%2F13%2Fhellguard_unix_faq%2FM.1031923592.U0
2  http://blog.linux.org.tw/~jserv/archives/002041.html

没有评论 »

如何让自己写的服务器支持php?

五月 15, 2009 | c/c++, php | RSS 2.0

 写一个支持支持静态的文件的c服务器很简单,就是些文件目录等操作,如何写一个支持get方式php的呢?
很简单的可以用一个shell搞定 ,例如,但是如何支持post等操作呢?
#include <stdio.h>
void command_mess(char *command, char *buf, int length)
{
    FILE   *stream;

    stream = popen(command,”r”);
    fread( buf, sizeof(char), length,  stream);
    pclose( stream );
    return;
}

int main( void )
{
    char buf[4096] = “”;  //请注意系统命令要输出的数据大小,小心得到的数据不全哦
    char com[64] = “/home/liufabin/php/bin/php test.php”;
    command_mess(com, buf, sizeof(buf));
    printf(”Message:%s”,buf);
    return 0;

}

没有评论 »

c获取文件的大小的两种方法和行读取

五月 6, 2009 | c/c++, linux, 网站架构 | RSS 2.0

1 fseek移动指针获取
#include <stdio.h>
#include <stdlib.h>

long filesize( FILE *fp )
{
    long int save_pos;
    long size_of_file;

    /* Save the current position. */
    save_pos = ftell( fp );

    /* Jump to the end of the file. */
    fseek( fp, 0L, SEEK_END );

    /* Get the end position. */
    size_of_file = ftell( fp );

    /* Jump back to the original position. */
    fseek( fp, save_pos, SEEK_SET );

    return( size_of_file );
}

int main( void )
{
    FILE *fp;

    fp = fopen( “aa.txt”, “r” );

    if( fp != NULL ) {
        printf( “File size=%ld”, filesize( fp ) );
        fclose( fp );

        return EXIT_SUCCESS;
    }

    return EXIT_FAILURE;
}

2 stat获取

#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>

int main( void )  {    struct stat buf;

    if( stat( "file", &buf ) != -1 ) {      printf( "File size = %d", buf.st_size );    }    return EXIT_SUCCESS;

  }

但是是有区别的,如
参考fseek()。
  通过fseek()、ftell()两个函数,我们就可以随意访问文件的任何位置了,想了想好像操作文件就这么easy,实在也没有更多可说的了。对了,fseek()和ftell()存在一个潜在的问题就是他们限制文件的大小只能在long类型的表示范围以内,也就是说通过这种方式,只能打开2,000,000,000字节的文件,不过在绝大多数情况下似乎也已经够用了。如果需要打开更大的文件,你需要用到fgetpos()、fsetpos()函数了,那是另一个命题了。

#include <stdio.h>
#include <string.h>

int main()
{
    int  i;
    long k;
    char buf[100];
    long int save_pos;

    FILE *fp;

    fp=fopen(”aa.txt”,”rb”);
    for(i=1;i<10;i++)
    {
        fscanf(fp,”%[^]“,buf);
        //这句读取一行,直到遇到,停止,并把读到的内容放到buf里,而此时文件指针的位置指向
        printf(”%s”,buf);
        //k=strlen(buf);
        fseek(fp,1,SEEK_CUR);
    //跳过,则从下一行的开始读。这里主要是跳过换行符。如果为k的话,就是从第二行跳过k个字符的位置开始读,当然是不对的了。
        buf[0]=’0′;

    }
    fclose(fp);
    return 0;
}

没有评论 »

如何避免僵死进程

四月 8, 2009 | c/c++, linux | RSS 2.0

综合和参考了几个网友的文章和apue的,不一一列举,致谢!!!

在fork()/execve()过程中,假设子进程结束时父进程仍存在,而父进程fork()之前既没安装SIGCHLD信号处理函数调用waitpid()等待子进程结束,又没有显式忽略该信号,则子进程成为僵尸进程,无法正常结束,此时即使是root身份kill-9也不能杀死僵尸进程。补救办法是杀死僵尸进程的父进程(僵尸进程的父进程必然存在),僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程。

怎样来清除僵尸进程:
1.改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
2.把父进程杀掉。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
3.调用fork两次。

如何产生僵死进程:

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
if (0 == fork()) {
printf(”In the child process:%d”, getpid());
} else {
printf(”In the parent process:%d”, getpid());
sleep(10);
exit(0);
}
printf(”Pid:%d”, getpid());
return 0;
}

如何避免:

若调用成功则返回清理掉的子进程id,若调用出错则返回-1。父进程调用waitwaitpid时可能会:

  • 阻塞(如果它的所有子进程都还在运行)。

  • 带子进程的终止信息立即返回(如果一个子进程已终止,正等待父进程读取其终止信息)。

  • 出错立即返回(如果它没有任何子进程)。

这两个函数的区别是:

  • 如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在options参数中指定WNOHANG可以使父进程不阻塞而立即返回0。

  • wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。

可见,调用waitwaitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进

#include <sys/types.h>#include <sys/wait.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>

int main(void){ pid_t pid; pid = fork(); if (pid < 0) {  perror("fork failed");  exit(1); } if (pid == 0) {  int i;  for (i = 3; i > 0; i--) {   printf("This is the child");   sleep(1);  }  exit(3); } else {  int stat_val;  waitpid(pid, &stat_val, 0);  if (WIFEXITED(stat_val))   printf("Child exited with code %d", WEXITSTATUS(stat_val));  else if (WIFSIGNALED(stat_val))   printf("Child terminated abnormally, signal %d", WTERMSIG(stat_val)); } return 0;}

2 处理信号:#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include<sys/wait.h>

void proc_child(int SIGNO)
{
int pid = -1;
int stat;
pid = waitpid(-1, &stat, WNOHANG);
}

int main(int argc, char **argv)
{
signal(SIGCHLD, proc_child);
if (0 == fork()) {
printf(”In the child process:%d”, getpid());
} else {
printf(”In the parent process:%d”, getpid());
sleep(10);
exit(0);
}
printf(”Pid:%d”, getpid());
return 0;
}

3 忽略信号int main(int argc, char **argv){signal(SIGCHLD, SIG_IGN); //加入此句即可,忽略SIGCHLD信号if (0 == fork()) {printf("In the child process:%d", getpid());} else {printf("In the parent process:%d", getpid());sleep(10);exit(0);}printf("Pid:%d", getpid());return 0;}4 apue上的fork两次:

fork两次在防止僵死方面来说,就是因为儿子进程先退出,孙子进程就被init接管了,实际上与最初的父进程脱离了关系,就不会僵死了。

#include <stdio.h>#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>

int main(void)   {      pid_t pid;   

    if ((pid = fork()) < 0)       {           fprintf(stderr,"Fork error!");           exit(-1);       }       else if (pid == 0) /* first child */      {            if ((pid = fork()) < 0)           {                fprintf(stderr,"Fork error!");               exit(-1);           }           else if (pid > 0)               exit(0); /* parent from second fork == first child */          /*           * We're the second child; our parent becomes init as soon           * as our real parent calls exit() in the statement above.           * Here's where we'd continue executing, knowing that when           * we're done, init will reap our status.           */          sleep(2);           printf("Second child, parent pid = %d", getppid());           exit(0);       }   

    if (waitpid(pid, NULL, 0) != pid) /* wait for first child */      {           fprintf(stderr,"Waitpid error!");           exit(-1);       }   

    /*       * We're the parent (the original process); we continue executing,       * knowing that we're not the parent of the second child.       */      exit(0);   }   5 static voidsig_child(){    waitpid(-1, NULL, 0);}[...]signal(SIGCHLD, sig_child)sig_child这个函数有问题。这个函数的作用是每当有一个进程退出时,便会调用一次sig_child,sig_child便会调用waitpid处理一个已退出的子进程。但是假如程序正在sig_child里面,这时又有另外一个子进程退出了,这时该怎么处理呢?处理的方法应该是不会有另外一个sig_child响应,于是这时便有2个子进程退出了,但是sig_child只能处理一个,于是便有一个退出的子进程成了僵死进程了。

于是把sig_child改成:
static void
sig_child()
{
    while (waitpid(-1, NULL, 0) > 0);
}
 
这样假如程序正在sig_child里面,这时又有另外n个子进程退出了,由于用了while,于是sig_child便会将所以退出的子进程“一网打尽”。

这是一种处理僵死进程的方法,另外还有2种:
signal(SIGCHLD, SIG_IGN);
忽略SIGCHLD信号,父进程不需要处理,直接把退出的子进程推给init进程处理。

struct sigaction    sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = SA_NOCLDWAIT;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGCHLD, &sa, NULL) < 0) {
    exit(-1);
}

没有评论 »

socket笔记

四月 1, 2009 | c/c++, linux, 网站架构 | RSS 2.0

1什么是socket 利用标准的unix文件表述夫和别的程序进行交流的方式

unix中一切都是文件,unix程序i/o交换时通过多谢文件表述夫,一个文件表述夫就是一个简单的整形的和打开文件相关的东西。 thatfile can be a network connection, a

FIFO,a pipe, a terminal, a real on-the-disk file, or just about anything

else.Everything in Unix is a file! So when you want to communicate with

anotherprogram over the Internet you’re gonna do it through a file

descriptor,you’d better believeit.你可能要问,在网络交换中我如何得到文件表述夫呢?调用socket,它将返回一个文件夫,你和它进行交流调用通过专门的socketsendrecv。但是你现在可能会说,既然是文件表述夫,那我为什么不能用writeread呢?简单的说,可以,复杂的,但是在数据传输中sendrecv能更好的得到控制。

有多种socketdarpainternetsocket网络socket,路径名在本地节点,x25地址。。。。可能还支持多种unix支持的。本文主要说的是网络socket。两种网络socket,其实是在说谎,为了怕吓着你,这里只介绍两种情况,介绍一种简单的状态协议的socket。流套接字,可靠如果你输出的socket按照顺序是12,到达的则是1,2的相反,你听说过telnet吧,它用的就是流套接字,你可以模仿http协议在telnet,的两边连接,在某些方面类似,标准的输入输出流,提供一个有序的可靠的,双字节流的链接,发送的数据确保不会丢失,复制和乱序到到,并且在这一过程中发生的错误也不会显示出来,大的消息背分片,传输,再重组。这很像一个文件流,接受大的数据,然后以笑数据块的格式将他们写入底层硬盘。流套接字的行为是可以遇见的。有类型sock_stream指定,在af_inet域中通过tcp/ip连接实现的。SOCK_DGRAM数据包套接字有时被称为无连接的socket.流套接字用的是传输控制协议,网际协议。数据包套接字也用ip路由,但是他们不用tcp协议,他们用udp协议。什么是无连接的?基本上是你在进行流套接字时不用去维持一个打开的连接,你建立一个包,分片,ip头,在目的信息上,发出去,不需要连接了,包包传简单的应用如:tftpbootp等。

你可能惊奇,如果数据包丢失,程序将如如何工作,myhumanfriend,在udp上层也有自己的协议,tftp协议每个包发出,接受方返回说我得到了,如果没有回复,5秒后,它将继续传输,直到得到了ack

网际七层协议:

*Application

*Presentation

*Session

*Transport

*Network

*Data Link

  • Physical

  • 四层协议

    * Application Layer (telnet, ftp, etc.)

  • * Host-to-Host Transport Layer (TCP, UDP)

  • * Internet Layer (IP and routing)

  • * Network Access Layer (was Network, Data Link, and Physical)

多种struct

structsockaddr {

unsignedshort sa_family; /* address family, AF_xxx */

char sa_data[14]; /* 14 bytes of protocol address */

};

af_inet域中:

structsockaddr_in (”in” for “Internet”.)

structsockaddr_in {

shortint sin_family; /* Address family */

unsignedshort int sin_port; /* Port number */

structin_addr sin_addr; /* Internet address */

unsignedchar sin_zero[8]; /* Same size as struct sockaddr */

};

/*Internet address (a structure for historical reasons) */

structin_addr {

unsignedlong s_addr;

};

字节顺序:

*htons()–”Host to Network Short”

*htonl()–”Host to Network Long”

*ntohs()–”Network to Host Short”

  • ntohl()–”Network to Host Long”

  • 为什么地址协议不用网络字节顺序?

  • A final point: why do sin_addr and sin_port need to be in Network Byte Order

  • in a struct sockaddr_in, but sin_family does not? The answer: sin_addr and

  • sin_port get encapsulated in the packet at the IP and UDP layers,

  • respectively. Thus, they must be in Network Byte Order. However, the

  • sin_family field is only used by the kernel to determine what type of

  • address the structure contains, so it must be in Host Byte Order. Also,

  • since sin_family does not get sent out on the network, it can be in Host

  • Byte Order.

库函数介绍

    inet_addr(), converts an IP address in numbers-and-dots notation

  • into an unsigned long. The assignment can be made as follows:

  • ina.sin_addr.s_addr = inet_addr(”132.241.5.10″);

  • Notice that inet_addr() returns the address in Network Byte Order

  • already–you don’t have to call htonl(). Swell!

  • 不要忘记了错误检查

  • 相反你也可以有iplong得到ip地址:

  • printf(”%s”,inet_ntoa(ina.sin_addr));

  • 注意事项

  • That will print the IP address. Note that inet_ntoa() takes a struct in_addr

  • as an argument, not a long. Also notice that it returns a pointer to a char.

  • This points to a statically stored char array within inet_ntoa() so that

  • each time you call inet_ntoa() it will overwrite the last IP address you

  • asked for. For example:

  • char *a1, *a2;

  • .

  • .

  • a1 = inet_ntoa(ina1.sin_addr); /* this is 198.92.129.1 */

  • a2 = inet_ntoa(ina2.sin_addr); /* this is 132.241.5.10 */

  • printf(”address 1: %s”,a1);

  • printf(”address 2: %s”,a2);

  • will print:

  • address 1: 132.241.5.10

  • address 2: 132.241.5.10

  • If you need to save the address, strcpy() it to your own character array.

  • That’s all on this topic for now. Later, you’ll learn to convert a string

  • like “whitehouse.gov” into its corresponding IP address

创建socket

#include<sys/types.h>

#include<sys/socket.h>

intsocket(int domain, int type, int protocol);

Butwhat are these arguments? First, domain should be set to “AF_INET”,just

likein the struct sockaddr_in (above.) Next, the type argument tells the

kernelwhat kind of socket this is: SOCK_STREAM or SOCK_DGRAM. Finally,just

setprotocol to “0″. (Notes: there are many more domains thanI’ve listed.

Thereare many more types than I’ve listed. See the socket() man page.Also,

there’sa “better” way to get the protocol. See thegetprotobyname() man

page.)

socket()simply returns to you a socket descriptor that you can use in later

systemcalls, or -1 on error. The global variable errno is set to the

error’svalue (see the perror() man page.)

bind

#include<sys/types.h>

#include<sys/socket.h>

intbind(int sockfd, struct sockaddr *my_addr, int addrlen);

例子:

#include<string.h>

#include<sys/types.h>

#include<sys/socket.h>

#defineMYPORT 3490

main()

{

intsockfd;

structsockaddr_in my_addr;

sockfd= socket(AF_INET, SOCK_STREAM, 0); /* do some error checking! */

my_addr.sin_family= AF_INET; /* host byte order */

my_addr.sin_port= htons(MYPORT); /* short, network byte order */

my_addr.sin_addr.s_addr= inet_addr(”132.241.5.10″);

bzero(&(my_addr.sin_zero),8); /* zero the rest of the struct */

/*don’t forget your error checking for bind(): */

bind(sockfd,(struct sockaddr *)&my_addr, sizeof(struct sockaddr));

注意:

my_addr.sin_port= 0; /* choose an unused port at random */

my_addr.sin_addr.s_addr= INADDR_ANY; /* use my IP address */

See,by setting my_addr.sin_port to zero, you are telling bind() tochoose

theport for you. Likewise, by setting my_addr.sin_addr.s_addr to

INADDR_ANY,you are telling it to automatically fill in the IP address of

themachine the process is running on.

.Theconnect() call is as follows:

#include<sys/types.h>

没有评论 »

数据结构队列(七)memcache源码

三月 25, 2009 | c/c++, linux | RSS 2.0

队列(Queue)是一种数据结构,可以在队列的一端插入元素而在队列的另一端删除元素。

  ( 1 )允许删除的一端称为 队头( Front )
  ( 2 )允许插入的一端称为 队尾( Rear )
  ( 3 )当队列中没有元素时称为 空队列
  ( 4 )队列亦称作先进先出( First In First Out )的线性表,简称为 FIFO 表

队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(即不允许 ” 加塞 ” ),每次离开的成员总是队列头上的(不允许中途离队),即当前 ” 最老的 ” 成员离队。

多任务系统是一个典型的队列示例,在其中完成作业的调度。假设有五个程序等待执行, 它们将被放入一个队列,如果有第六个程序要执行,它将被放在队列的末尾。队列中首位的程序首先执行.程序代码

#include <stdio.h>
#define maxsize 10
typedef struct
{
    int elem[maxsize];
    int front,rear;
}queue;
void init_queue(queue *cp)
{
    cp->front=0;
    cp->rear=0;
}
void en_queue(queue *cp,int x)
{
    if((cp->rear+1)%maxsize==cp->front)
        printf(”The quequ is full!!”);
    else
    {
        cp->rear=(cp->rear+1)%maxsize;
        cp->elem[cp->rear]=x;
    }
}
int dl_queue(queue *cp)
{
    if(cp->front==cp->rear)
        printf(”The queue is empty!!”);
    else
    {
        cp->front=(cp->front+1)%maxsize;
        return(cp->elem[cp->front]);
     }
}
void print(queue *cp)
{
    int i;
    for(i=cp->front+1;i<=cp->rear;i++)
    {
        printf(”[%d]“,cp->elem[i]);
    }
}
void main()
{
    int x,y;
    int select;
    queue *cp=NULL;
    init_queue(cp);
    do
    {
        printf(”(1) Input a stack data”);
        printf(”(2) Output a stack data”);
        printf(”(3) Exit”);
        printf(”Please select one:”);
        scanf(”%d”,&select);
        switch(select)
        {
            case 1:printf(”Please input the data:”);
                   scanf(”%d”,&x);
                   en_queue(cp,x);
                   printf(”The queue is: “);
                   print(cp);
                   break;
            case 2:y=dl_queue(cp);
                   printf(”The queue is: “);
                   print(cp);
                   printf(”The putout data is %d”,y);
                   break;
            case 3:break;
        }
    }
    while(select<3);
    getch();
}

memcached :
#include “memcached.h”
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <errno.h>

#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef USE_THREADS

#include <pthread.h>

#define ITEMS_PER_ALLOC 64

/* An item in the connection queue. */
/*链接队列项 */
typedef struct conn_queue_item CQ_ITEM;
struct conn_queue_item {
    int     sfd;
    int     init_state;
    int     event_flags;
    int     read_buffer_size;
    int     is_udp;
    CQ_ITEM *next;
};

/*链接 队列*/
/* A connection queue. */
typedef struct conn_queue CQ;
struct conn_queue {
    CQ_ITEM *head;
    CQ_ITEM *tail;
    pthread_mutex_t lock;
    pthread_cond_t  cond;
};

/* Lock for connection freelist */
static pthread_mutex_t conn_lock;

/* Lock for alternative item suffix freelist */
static pthread_mutex_t suffix_lock;

/* Lock for cache operations (item_*, assoc_*) */
static pthread_mutex_t cache_lock;

/* Lock for slab allocator operations */
static pthread_mutex_t slabs_lock;

/* Lock for global stats */
static pthread_mutex_t stats_lock;

/*cq的连表*/
/* Free list of CQ_ITEM structs */
static CQ_ITEM *cqi_freelist;
static pthread_mutex_t cqi_freelist_lock;

/*
 * Each libevent instance has a wakeup pipe, which other threads
 * can use to signal that they’ve put a new connection on its queue.
 没一个 libevent实例都有一个别 的线程用信号唤醒的管道,他们最早队列中起个链接
 */
typedef struct {
    pthread_t thread_id;        /* unique ID of this thread 线程id*/
    struct event_base *base;    /* libevent handle this thread uses 线程用到的libeven的处理t */
    struct event notify_event;  /* listen event for notify pipe 监听事件来通知管道*/
    int notify_receive_fd;      /* receiving end of notify pipe 接受结束通知管道 */
    int notify_send_fd;         /* sending end of notify pipe 发送结束管道 */
    CQ  new_conn_queue;         /* queue of new connections to handle 新 的链接处理*/
} LIBEVENT_THREAD;

static LIBEVENT_THREAD *threads;

/*
 * Number of threads that have finished setting themselves up.
 */
static int init_count = 0;
static pthread_mutex_t init_lock;
static pthread_cond_t init_cond;

static void thread_libevent_process(int fd, short which, void *arg);

/*
 * Initializes a connection queue.
 */
static void cq_init(CQ *cq) {
    pthread_mutex_init(&cq->lock, NULL);
    pthread_cond_init(&cq->cond, NULL);
    cq->head = NULL;
    cq->tail = NULL;
}

/*
 * Waits for work on a connection queue.
 */
static CQ_ITEM *cq_pop(CQ *cq) {
    CQ_ITEM *item;

    pthread_mutex_lock(&cq->lock);
    while (NULL == cq->head)
        pthread_cond_wait(&cq->cond, &cq->lock);
    item = cq->head;
    cq->head = item->next;
    if (NULL == cq->head)
        cq->tail = NULL;
    pthread_mutex_unlock(&cq->lock);

    return item;
}

/*
 * Looks for an item on a connection queue, but doesn’t block if there isn’t
 * one.
 * Returns the item, or NULL if no item is available
 */
static CQ_ITEM *cq_peek(CQ *cq) {
    CQ_ITEM *item;

    pthread_mutex_lock(&cq->lock);
    item = cq->head;
    if (NULL != item) {
        cq->head = item->next;
        if (NULL == cq->head)
            cq->tail = NULL;
    }
    pthread_mutex_unlock(&cq->lock);

    return item;
}

/*
 * Adds an item to a connection queue.
 */
static void cq_push(CQ *cq, CQ_ITEM *item) {
    item->next = NULL;

    pthread_mutex_lock(&cq->lock);
    if (NULL == cq->tail)
        cq->head = item;
    else
        cq->tail->next = item;
    cq->tail = item;
    pthread_cond_signal(&cq->cond);
    pthread_mutex_unlock(&cq->lock);
}

/*
 * Returns a fresh connection queue item.
 */
static CQ_ITEM *cqi_new() {
    CQ_ITEM *item = NULL;
    pthread_mutex_lock(&cqi_freelist_lock);
    if (cqi_freelist) {
        item = cqi_freelist;
        cqi_freelist = item->next;
    }
    pthread_mutex_unlock(&cqi_freelist_lock);

    if (NULL == item) {
        int i;

        /* Allocate a bunch of items at once to reduce fragmentation */
        item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC);
        if (NULL == item)
            return NULL;

        /*
         * Link together all the new items except the first one
         * (which we’ll return to the caller) for placement on
         * the freelist.
         */
        for (i = 2; i < ITEMS_PER_ALLOC; i++)
            item[i - 1].next = &item[i];

        pthread_mutex_lock(&cqi_freelist_lock);
        item[ITEMS_PER_ALLOC - 1].next = cqi_freelist;
        cqi_freelist = &item[1];
        pthread_mutex_unlock(&cqi_freelist_lock);
    }

    return item;
}

/*
 * Frees a connection queue item (adds it to the freelist.)
 */
static void cqi_free(CQ_ITEM *item) {
    pthread_mutex_lock(&cqi_freelist_lock);
    item->next = cqi_freelist;
    cqi_freelist = item;
    pthread_mutex_unlock(&cqi_freelist_lock);
}

/*
 * Creates a worker thread.
 */
static void create_worker(void *(*func)(void *), void *arg) {
    pthread_t       thread;
    pthread_attr_t  attr;
    int             ret;

    pthread_attr_init(&attr);

    if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) {
        fprintf(stderr, “Can’t create thread: %s”,
                strerror(ret));
        exit(1);
    }
}

/*
 * Pulls a conn structure from the freelist, if one is available.
 */
conn *mt_conn_from_freelist() {
    conn *c;

    pthread_mutex_lock(&conn_lock);
    c = do_conn_from_freelist();
    pthread_mutex_unlock(&conn_lock);

    return c;
}

/*
 * Adds a conn structure to the freelist.
 *
 * Returns 0 on success, 1 if the structure couldn’t be added.
 */
bool mt_conn_add_to_freelist(conn *c) {
    bool result;

    pthread_mutex_lock(&conn_lock);
    result = do_conn_add_to_freelist(c);
    pthread_mutex_unlock(&conn_lock);

    return result;
}

/*
 * Pulls a suffix buffer from the freelist, if one is available.
 */
char *mt_suffix_from_freelist() {
    char *s;

    pthread_mutex_lock(&suffix_lock);
    s = do_suffix_from_freelist();
    pthread_mutex_unlock(&suffix_lock);

    return s;
}

/*
 * Adds a suffix buffer to the freelist.
 *
 * Returns 0 on success, 1 if the buffer couldn’t be added.
 */
bool mt_suffix_add_to_freelist(char *s) {
    bool result;

    pthread_mutex_lock(&suffix_lock);
    result = do_suffix_add_to_freelist(s);
    pthread_mutex_unlock(&suffix_lock);

    return result;
}

/****************************** LIBEVENT THREADS *****************************/

/*
 * Set up a thread’s information.
 */
static void setup_thread(LIBEVENT_THREAD *me) {
    if (! me->base) {
        me->base = event_init();
        if (! me->base) {
            fprintf(stderr, “Can’t allocate event base”);
            exit(1);
        }
    }

    /* Listen for notifications from other threads */
    event_set(&me->notify_event, me->notify_receive_fd,
              EV_READ | EV_PERSIST, thread_libevent_process, me);
    event_base_set(me->base, &me->notify_event);

    if (event_add(&me->notify_event, 0) == -1) {
        fprintf(stderr, “Can’t monitor libevent notify pipe”);
        exit(1);
    }

    cq_init(&me->new_conn_queue);
}

/*
 * Worker thread: main event loop
 */
static void *worker_libevent(void *arg) {
    LIBEVENT_THREAD *me = arg;

    /* Any per-thread setup can happen here; thread_init() will block until
     * all threads have finished initializing.
     */

    pthread_mutex_lock(&init_lock);
    init_count++;
    pthread_cond_signal(&init_cond);
    pthread_mutex_unlock(&init_lock);

    return (void*) event_base_loop(me->base, 0);
}

/*
 * Processes an incoming “handle a new connection” item. This is called when
 * input arrives on the libevent wakeup pipe.
 */
static void thread_libevent_process(int fd, short which, void *arg) {
    LIBEVENT_THREAD *me = arg;
    CQ_ITEM *item;
    char buf[1];

    if (read(fd, buf, 1) != 1)
        if (settings.verbose > 0)
            fprintf(stderr, “Can’t read from libevent pipe”);

    item = cq_peek(&me->new_conn_queue);

    if (NULL != item) {
        conn *c = conn_new(item->sfd, item->init_state, item->event_flags,
                           item->read_buffer_size, item->is_udp, me->base);
        if (c == NULL) {
            if (item->is_udp) {
                fprintf(stderr, “Can’t listen for events on UDP socket”);
                exit(1);
            } else {
                if (settings.verbose > 0) {
                    fprintf(stderr, “Can’t listen for events on fd %d”,
                        item->sfd);
                }
                close(item->sfd);
            }
        }
        cqi_free(item);
    }
}

/* Which thread we assigned a connection to most recently. */
static int last_thread = -1;

/*
 * Dispatches a new connection to another thread. This is only ever called
 * from the main thread, either during initialization (for UDP) or because
 * of an incoming connection.
 */
void dispatch_conn_new(int sfd, int init_state, int event_flags,
                       int read_buffer_size, int is_udp) {
    CQ_ITEM …

没有评论 »

高效产生不重复的随机数

三月 24, 2009 | c/c++, 数学, 数据结构算法, 软件工程/编程技巧/设计模式 | RSS 2.0

编程珠玑里面的

for(i = 0; i < n; i++)
{
x[i] = i;
}
for(i = 0; i < k; i++)
{
t = rand(i,n-1);
swap(x[i], x[t]);
out(x[i]);
}

没有评论 »

数据结构系列循环队列(六 )

三月 20, 2009 | c/c++, 数据结构算法 | RSS 2.0

引用:http://learn.akae.cn/media/ch12s05.html
我们介绍一种新的数据结构--环形队列(Circular Queue)。把queue数组想像成一个圈,head和tail指针仍然是一直增大的,当指到数组末尾时就自动回到数组开头,就像两个人围着操场赛跑,沿着它们跑的方向看,从head到tail之间是队列的有效元素,从tail到head之间是空的存储位置,head追上tail就表示队列空了,tail追上head就表示队列的存储空间满了。如下图所示
数据结构系列循环队列(六 ) - 玉树临风 - 小和尚真情无限

#define MAXQSIZE 100

typedef struct {
    int *base;//循环队列的存储空间
    int front ;
    int rear;
}SqQueue;
/*初始化*/
int InitQueue(SqQueue  *Q) {
    Q->base = (int *)malloc(MAXQSIZE*sizeof(int));
    if(!Q->base) return -1;

    Q->front = 0;
    Q->rear = 0;
    return 0;
}
/*元素e加入队,成功为0 ,否则返回1*/
int EnQueue(SqQueue *Q,int e) {
    if((Q->rear+1)%MAXQSIZE == Q->font) return -1;
    Q->base[Q->rear] = e;
    Q->rear = (Q->rear +1)%MAXQSIZE;
}
/*出队列*/
int DeQueue(SqQueue *Q,int *c) {
    if(Q->rear == Q->front) return -1;
    *e = Q->base[Q->front];
    Q->front = (Q->front+1)%MAXQSIZE;
    return 0;

}

没有评论 »