Chinaunix首页 | 论坛 | 博客
  • 博客访问: 61435
  • 博文数量: 20
  • 博客积分: 1031
  • 博客等级: 少尉
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-11 14:22
文章分类

全部博文(20)

文章存档

2011年(2)

2010年(4)

2009年(14)

我的朋友

分类: C/C++

2011-06-15 16:36:40


2011.6.15 ______________________________________________________________

写了一个 计算cpu使用率 的函数,如下:

#define get_cpu_time(us, ni, sy, idle, io, ir, so, st, gu) \
    fp = fopen("/proc/stat", "rb"); \
    memset (CpuStatBuf, 0, sizeof CpuStatBuf); \
    fread (CpuStatBuf, 1, sizeof CpuStatBuf, fp); \
    fclose (fp); \
    \
    line = strstr (CpuStatBuf, " "); us = atoi (line); \
    line = strstr (line+2, " "); ni = atoi (line); \
    line = strstr (line+1, " "); sy = atoi (line); \
    line = strstr (line+1, " "); idle = atoi (line); \
    line = strstr (line+1, " "); io = atoi (line); \
    line = strstr (line+1, " "); ir = atoi (line); \
    line = strstr (line+1, " "); so = atoi (line); \
    line = strstr (line+1, " "); st = atoi (line); \
    line = strstr (line+1, " "); gu = atoi (line);

/*==================================================================
//函数名 : CpuUseRate
//描述 : 从 /proc/stat 文件里获取cpu 使用信息, 计算出cpu使用率, 并打印到屏幕上;
//
//作者 : llb
//日期 : 2011-6-14
//
//输入参数 : 无;
//输出参数 : 无;
//
//返回值 : 无;
//备注1 :
// 参考 man proc 的/proc/stat 这段:
// /proc/stat
// kernel/system statistics. Varies with architecture. Common entries include:
//
// cpu 3357 0 4313 1362393
// The amount of time, measured in units of USER_HZ (1/100ths of a second on most architectures, use
// sysconf(_SC_CLK_TCK) to obtain the right value), that the system spent in user mode, user mode with low priority
// (nice), system mode, and the idle task, respectively. The last value should be USER_HZ times the second entry in
// the uptime pseudo-file.
//
// In Linux 2.6 this line includes three additional columns: iowait - time waiting for I/O to complete (since
// 2.5.41); irq - time servicing interrupts (since 2.6.0-test4); softirq - time servicing softirqs (since
// 2.6.0-test4).
//
// Since Linux 2.6.11, there is an eighth column, steal - stolen time, which is the time spent in other operating
// systems when running in a virtualized environment
//
// Since Linux 2.6.24, there is a ninth column, guest, which is the time spent running a virtual CPU for guest oper‐
// ating systems under the control of the Linux kernel.
//
// ...
//
//备注2 :
// 本函数上方定义了一个宏, 使用本函数内部变量来获得相应的cpu 时间;
//=================================================================*/

void CpuUseRate (void)
{
    char CpuStatBuf[256];
    FILE *fp;
    char *line;

    // 见本函数注解, 根据 man proc 的/proc/stat 这段, 声明下面这些变量, 依次分别对应:

    // user mode, user mode with low priority, system mode, idle task, iowait, irq, softirq, steal, guest;

    int us1 = 0, ni1 = 0, sy1 = 0, idle1 = 0, io1 = 0, ir1 = 0, so1 = 0, st1 = 0, gu1 = 0;
    int us2 = 0, ni2 = 0, sy2 = 0, idle2 = 0, io2 = 0, ir2 = 0, so2 = 0, st2 = 0, gu2 = 0;
    int used = 0;
    int total = 0;

    double rate = 0;


    get_cpu_time(us1, ni1, sy1, idle1, io1, ir1, so1, st1, gu1);

    // 睡眠200ms后再取下一组值;

    usleep (200000);

    get_cpu_time(us2, ni2, sy2, idle2, io2, ir2, so2, st2, gu2);


    used = (us2 + ni2 + sy2 + io2 + ir2 + so2 + st2 + gu2) - (us1 + ni1 + sy1 + io1 + ir1 + so1 + st1 + gu1);
    total = (us2 + ni2 + sy2 + io2 + ir2 + so2 + st2 + gu2 + idle2) - (us1 + ni1 + sy1 + io1 + ir1 + so1 + st1 + gu1 + idle1);
    rate = (double) (100 * used) / (double) total;


    printf ("cpu use rate: %.1f %%\n", rate);
}






2011.6.16 ______________________________________________________________  

局部数组初始化问题:

// 数组初始化问题, 重点关注 局部数组的初始化写法, 和局部数组没有初始化的后果;
//
// 全局数组的初始化是 C语言规定的(?), 因此本程序中 c数组的值都为0, 但对 未初始化的数组b 的处理则是应该注意的, 这里其值是未定的;
//
// 数组a 只初始化了第一个元素, 整个数组其余未初始化的元素都被初始化为0, 由此可以用类似 本程序声明数组a 的写法来初始化数组;


#include <stdio.h>

unsigned char c[5];

int main (void)
{
    int i=0;
    unsigned char a[5] = {0x10};
    unsigned char b[5];

    for (i=0; i<sizeof a; i++) printf ("%x ", a[i]); printf ("\n");
    for (i=0; i<sizeof b; i++) printf ("%x ", b[i]); printf ("\n");
    for (i=0; i<sizeof c; i++) printf ("%x ", c[i]); printf ("\n");

    return 0;
}






2011.7.22 ______________________________________________________________  

从下面这个网页知道一个内核常用的写法:
http://hi.baidu.com/deep_pro/blog/item/f6522b36e53f37370b55a9c2.html

无论是Linux内核还是其他著名的c、c++库里都能见到 do{} while (0);这样的写法看似没有意义,其实出自名家之手,是在宏定义里使用的...


文章中讲了一个例子,定义了一个宏,释放内存同时把指针置为NULL,相当不错,以后用起来!:
#define  SAFE_FREE(p)  do {free(p);p=NULL;} while(0)

文章中也讲到,在if 后面尽量用“{}”把后面的语句括起来,以避免不必要的错误;





2011.7.26 ______________________________________________________________  

在网名为deep_pro 的博客找到一些有营养的东西,主要是C语言方面的,摘录如下

http://hi.baidu.com/deep_pro/blog/category/cר%BCһ%FD%C0%DB

1、
让死循环温和点

以前没意识到这个问题,这里说得很好:
http://hi.baidu.com/deep_pro/blog/item/46370d4322892c1f72f05d16.html

初学编程,经常有这样的问题:我要不断监听一个事件,看看是否满足条件再进行下一步操作
当然在某些事件被抽象成文件读写之后,select、poll、epoll这些异步读写机制能让你的代码更有效率
inotify能够监听文件变化,其他的情况我就不知道了,...

那么,当你迫不得已必须写一个死循环来监测某个事件时,就应该让这个死循环尽可能温和些
不要每次都死皮赖脸硬要内核把你调度出去,主动放弃cpu才是好孩子

据说vxworks和windows 可以这么做:
while(1)
{
    sleep(0);
}

linux下似乎只能这么做:
while(1)
{
    sched_yield();
}


2、
求一个字节(8bit)有几位为"1"的O(1)解

据说这是一道面试题,在这里:
http://hi.baidu.com/deep_pro/blog/item/89aaf43885edc922b9998fe3.html

问题:对于一个字节(8bit)的数据,求其中“1”的个数,要求算法的执行效率尽可能地高。
 分析:...。你或许已经想到很多方法,譬如除、余操作,位操作等,但都不是最快的。...

最佳的答案是用一个 256元素的查找表 来解答,代码如下:

#include <stdio.h>

#define BYTE unsigned char

/* 定义查找表 */
BYTE numTable[256] =
{
    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,
    3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3,
    4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,
    3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3,
    4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
    6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4,
    5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3,
    4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4,
    4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6,
    7, 6, 7, 7, 8
};

int main(int argc, char *argv[])
{
    int b = 0;
    BYTE a = 0;

    /* 接收用户输入 */
    printf("\nPlease Input a BYTE(0~255):");
    scanf("%d", &b);
    a = b;

    /* 计算1 的个数 */
    /* 用BYTE 直接作为数组的下标取出1 的个数,妙哉! */
    printf("\nthe num of 1 in the BYTE is %d\n", numTable[a]);

    return 0;
}


前面也说到可以用 除法 和 移位法,还有用switch case的方法,都比较笨拙,不过也可以看看 :)





2011.7.27 ______________________________________________________________

经常看到打印的字符有颜色,如第一个就曾经想用颜色来打印,但是没成功,这里把打印有颜色字符的方法记录下来,以备后用 :)

主要从这里知道怎么做的:
Linux下 printf 输出字符串的颜色
http://blogold.chinaunix.net/u3/116920/showart.php?id=2515365

也把上面链接的内容复制到这里来

格式:
printf("\033[字背景颜色;字体颜色m字符串\033[0m" );

例子:
printf("\033[41;32m字体背景是红色,字是绿色\033[0m\n");
41是字背景颜色, 32是字体的颜色, 字体背景是红色,字是绿色是字符串. 后面的\033[0m是控制码.

// 插一句,可以对照下面定义的代码看上面的例子 ^_^


颜色代码:
字背景颜色范围: 40--49 字颜色: 30--39
40: 黑 30: 黑
41: 红 31: 红
42: 绿 32: 绿
43: 黄 33: 黄
44: 蓝 34: 蓝
45: 紫 35: 紫
46: 深绿 36: 深绿
47: 白色 37: 白色

ANSI控制码:
\033[0m 关闭所有属性  
\033[1m 设置高亮度
\03[4m 下划线
\033[5m 闪烁
\033[7m 反显
\033[8m 消隐
\033[30m -- \033[37m 设置前景色
\033[40m -- \033[47m 设置背景色
\033[nA 光标上移n行
\03[nB 光标下移n行
\033[nC 光标右移n行
\033[nD 光标左移n行
\033[y;xH设置光标位置
\033[2J 清屏
\033[K 清除从光标到行尾的内容
\033[s 保存光标位置
\033[u 恢复光标位置
\033[?25l 隐藏光标
\33[?25h 显示光标

这样, 在某些时候就可以实现动态的输出.





2011.8.4 ______________________________________________________________

linux 命令的参数解析,一般用getopt(),getopt_long() 可以用长的选项名,也兼容短选项,因此适应更多场合,这里把这个函数的用法作一个简单的小结,写程序的时候可以参考 ^_^

也说一下,这个用法主要来自这里:
http://blog.csdn.net/ast_224/article/details/3861625

先把上面链接中的程序给出来,然后再来看具体细节:

#include <stdio.h>
#include <getopt.h>
char *l_opt_arg;
char* const short_options = "nbl:";
struct option long_options[] = {
     { "name", 0, NULL, 'n' },
     { "bf_name", 0, NULL, 'b' },
     { "love", 1, NULL, 'l' },
     { 0, 0, 0, 0},
};
int main(int argc, char *argv[])
{
     int c;
     while((c = getopt_long (argc, argv, short_options, long_options, NULL)) != -1)
     {
         switch (c)
         {
         case 'n':
             printf("My name is XL./n");
             break;
         case 'b':
             printf("His name is ST./n");
             break;
         case 'l':
             l_opt_arg = optarg;
             printf("Our love is %s!/n", l_opt_arg);
             break;
         }
     }
     return 0;
}


再来看一下 getopt_long() 的manual:
int getopt_long(int argc, char * const argv[],
                const char *optstring,
                const struct option *longopts, int *longindex);

其中的关键点在 struct option *longopts,这个结构体声明如下:
struct option {
    const char *name;
    int has_arg;
    int *flag;
    int val;
};

其中各个元素的含义如下:
The meanings of the different fields are:

name is the name of the long option.

has_arg
is: no_argument (or 0) if the option does not take an argument; required_argument (or 1) if the option requires
an argument; or optional_argument (or 2) if the option takes an optional argument.

flag specifies how results are returned for a long option. If flag is NULL, then getopt_long() returns val. (For
example, the calling program may set val to the equivalent short option character.) Otherwise, getopt_long()
returns 0, and flag points to a variable which is set to val if the option is found, but left unchanged if the
option is not found.

val is the value to return, or to load into the variable pointed to by flag.

其中的关键又在 flag,上面也说了,如果这个flag 为NULL,那么getopt_long() 就返回 val的值,也即结构体指针变量 longopts 指向的第四个元素;

因此才有上面代码里这样的写法:
while ( (c=getopt_long()) != -1)
{
    switch (c)
    {
    case 'n'
    ...
    }
}

今天把部分程序用在一个公司代码里,发现了一个地方:
char* const short_options = "nbl:";

如果某个短选项用了 : 号,那么后面就要带参数,所以如果不需要带参数,那就只要 "nbl" 就可以了,不过这是短选项,是不是需要带参数要与长选项对应起来,也就是要与  struct option long_options[] = {} 对应起来;





2011.8.12 ______________________________________________________________

sizeof 一个需要注意的地方

sizeof 只是一个c语言的操作符,不是一个函数。可以直接这样用:sizeof aVary,得到变量aVary 占用的内存空间;

但是最好这样写 sizeof (aVary),因为有时候会不经意写出这样的代码来: sizeof int,而这在gcc编译时是会报错的,如下所示:
[lb@localhost sizeof]$ make sizeofint
gcc -Wall -g -Wl,-rpath=/usr1/lib sizeofint.c -o sizeofint
sizeofint.c: In function ‘main’:
sizeofint.c:6: error: expected expression before ‘int’
make: *** [sizeofint] Error 1

代码如下:

#include

int main (void)
{
    printf ("%d\n", sizeof int); // wrong using of sizeof;
    return 0;
}


这里有sizeof 更详细的说明:
http://blogold.chinaunix.net/u/20828/showart_438003.html





2011.8.12 ______________________________________________________________

接下来是蛮重要的内容,请看下面 ^_^


当结构体里有 数组类型但数组长度为0 的成员,或者有 指针类型 的成员时,下面的代码或许可以给一些编程的参考:

// 本程序说明结构体中两种比较特殊成员的基本属性和简单用法:
// 1、结构体里有 数组长度为0的成员, 像下面的 struct struct_mumber_array 的 array;
// 2、结构体里有 指针成员, 像下面的 struct struct_mumber_pointer 的 pointer;


#include
#include // malloc();

struct struct_mumber_array
{
    unsigned char num;
    unsigned int array[0];
};

struct struct_mumber_pointer
{
    unsigned char num;
    unsigned int *pointer;
};

int main (void)
{
    struct struct_mumber_array *a = NULL, aa;
    struct struct_mumber_pointer *b = NULL, bb;

    // 注意下面的sizeof (aa), 实际上 a 得到的空间是4;
    a = (struct struct_mumber_array *) malloc (sizeof (struct struct_mumber_array));
    printf ("%p, %p\n", a, a->array);

    // b 得到的空间是8;
    b = (struct struct_mumber_pointer *) malloc (sizeof (struct struct_mumber_pointer));
    // &(b->pointer) 对应的是 a->array, 而 b->pointer 是一个空的值;
    // b->pointer 是一个指针变量, &(b->pointer) 取得 保存该变量的 地址值;
    printf ("%p, %p, %p, %d, %d\n", b, &(b->pointer), b->pointer, b->pointer, NULL);

    printf ("%d, %d\n", sizeof (aa), sizeof (bb));
    printf ("%d, %d\n", sizeof (struct struct_mumber_array), sizeof (struct     struct_mumber_pointer));
    return 0;
}






2011.8.17 ______________________________________________________________

又学到东西了,看看这个:

char i;
for(i=0; i {
    printf("%02x ", data[i]);
}

看起来没什么问题,不过编译时会有告警:
...: warning: array subscript has type 'char'

这个告警的意思经同事提醒知道是:
数组的下标用了类型'char',这估计是不被允许的;

也就是说 subscript 是下标的意思;





2011.8.30 ______________________________________________________________

今天通过一个例子更加清楚了 共享内存 的用法,例子来自这里:
http://blog.chinaunix.net/space.php?uid=13670711&do=blog&cuid=2034932shm_com.h

不过上面网页的例子程序有一些错误,编译的时候都暴露出来了,修改后的代码如下:

// shm_read.c


#include
#include
#include
#include

#include
#include

#include "shm_com.h"

// 2 我们的第一个程序用于消费者。在包含头文件之后,我们通过调用shmget函数,指定IPC_CREAT位来创建一个共享内存段(我们共享内存结构的大小)

int main (void)
{
    int running = 1;
    void *shared_memory = (void *)0;
    struct shared_use_st *shared_stuff;
    int shmid;

    srand ((unsigned int) getpid());

    shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);

    if(shmid == -1)
    {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }



    // 3 我们现在使用共享内存可以为程序所访问:

    shared_memory = shmat(shmid, (void *)0, 0);
    if(shared_memory == (void *)-1)
    {
        fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }

    printf("Memory attached at %X\t shmid: %d\n", (int)shared_memory, shmid);
    printf("Memory attached at %p\t shmid: %d\n", shared_memory, shmid);



    // 4 程序的接下来部分将shared_memroy段赋给shared_stuff,后者会输出written_by_you中的任何文本。程序继续循环直到 written_by_you中的文本为end。sleep调用会强制消费者停留在其临界区中,这会使得生产者程序等待。

    shared_stuff = (struct shared_use_st *)shared_memory;
    shared_stuff->written_by_you = 0;

    running = 1;
    while(running)
    {
        sleep(rand() % 4);
        if(shared_stuff->written_by_you)
        {
            printf("You wrote: %s\t rand()%%4: %d\n", shared_stuff->some_text, rand() % 4);

            //sleep(rand() % 4); // 放在这里不会生效, 为什么? 因为这是一个死循环, 当有东西写到共享内存的时候, cpu完全被占住了, 读共享内存值的事情 不会被执行到?
            shared_stuff->written_by_you = 0;

            if(strncmp(shared_stuff->some_text, "end", 3)==0)
            {
                running = 0;
            }
        }
    }



    // 5 最后共享内存被分离并被删除:

    if(shmdt(shared_memory)==-1)
    {
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }

    if(shmctl(shmid, IPC_RMID, 0)==-1)
    {
        fprintf(stderr, "shmctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}


这里有sizeof 更详细的说明:

先把上面链接中的程序给出来,然后再来看具体细节:

// shm_write.c



// 6 我们的第二个程序,shm_write.c,是生产者程序;他允许我们进入消费者的数据。这个程序与shm_read.c程序十分相似:

#include
#include
#include
#include

#include
#include
#include

#include "shm_com.h"

int main (void)
{
    int running = 1;
    void *shared_memory = (void *)0;
    struct shared_use_st *shared_stuff;
    char buffer[BUFSIZ];
    int shmid;

    shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666 | IPC_CREAT);

    if(shmid == -1)
    {
        fprintf(stderr, "shmget failed\n");
        exit(EXIT_FAILURE);
    }

    shared_memory = shmat(shmid, (void *)0, 0);
    if(shared_memory == (void *)-1)
    {
   
    fprintf(stderr, "shmat failed\n");
        exit(EXIT_FAILURE);
    }

    printf("Memory attached at %X\t shmid: %d\n", (int)shared_memory, shmid);

    shared_stuff = (struct shared_use_st *)shared_memory;

    while(running)
    {
        while(shared_stuff->written_by_you == 1)
        {
            sleep(2);
            printf("waiting for client...\n");
        }

        printf("Enter some text: ");
        fgets(buffer, BUFSIZ, stdin);

        strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
        shared_stuff->written_by_you = 1;

        if(strncmp(buffer, "end", 3) == 0)
        {
            running = 0;
        }
    }

    if(shmdt(shared_memory) == -1)
    {
        fprintf(stderr, "shmdt failed\n");
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}


阅读(836) | 评论(0) | 转发(0) |
0

上一篇:bash 与 shell编程

下一篇:没有了

给主人留下些什么吧!~~