正确用DD测试磁盘读写速度

Publish: October 17, 2016 Category: Shell No Comments

以下几种方式测试磁盘读写速度的区别:

# 仅得到写缓存的速度
dd bs=1M count=128 if=/dev/zero of=test

# 当sync做准备开始往磁盘上写数据时,前面的dd已经显示错误的‘写入速度’
dd bs=1M count=128 if=/dev/zero of=test; sync

# 读取128M数据到内存并写入到磁盘上所用时间 【比较符合实际】
dd bs=1M count=128 if=/dev/zero of=test conv=fdatasync

# 每次读1M后就要先把这1M写入磁盘,重复128次,基本上没用到写缓存
dd bs=1M count=128 if=/dev/zero of=test oflag=dsync

建议使用:

dd bs=1M count=128 if=/dev/zero of=test conv=fdatasync

因为这种方式最接近计算机实际操作,所以测出来的数据最有参考价值

例子:

# dd bs=10M count=128 if=/dev/zero of=test conv=fdatasync
128+0 records in
128+0 records out
1342177280 bytes (1.3 GB) copied, 4.60449 s, 291 MB/s

结果为:291MB/s


原则上:

  • 可以通过使用dd if=/dev/zero of=/file 来测试磁盘的纯写入性能。

  • 使用dd if=/file of=/dev/null 来测试磁盘的纯读取性能。

  • 使用dd if=/file1 of=/file2 来测试磁盘的读写性能。


测试硬盘的结果如下

(1)测试纯写入性能

#dd if=/dev/zero of=test bs=1M count=64 conv=fdatasync oflag=direct
64+0 records in
64+0 records out
67108864 bytes (67 MB) copied, 0.0710237 s, 945 MB/s

结果为945 MB/s。


(1)测试纯读取性能

# dd if=./test of=/dev/null bs=1M count=64 iflag=direct
64+0 records in
64+0 records out
67108864 bytes (67 MB) copied, 0.0283407 s, 2.4 GB/s

结果为2.4GB/s。

使用pipe进行进程间通讯

Publish: September 23, 2016 Category: C/C++ No Comments

    使用pipe进行进程间通讯,pipe只能在共同血缘(父子进程)进程中使用。

一、父子进程间通讯:

/*
 * 双向管道流模式: 父子进程互相读写
 * 
 *    --------      ---------------     --------
 *   | 父进程  |    |    UNIX 内核  |    | 子进程  |
 *   |        |    |===============|    |        |
 *   | pfd1[1]|--->|输入  管道I  输出|--->| pfd1[0]|
 *   |        |    |===============|    |        |
 *   | pfd2[0]|<---|输出  管道II 输入|<---| pfd2[1]|
 *   |        |    |               |    |        |
 *    --------      ---------------      --------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    int pfd1[2], pfd2[2];
    pid_t pid;
    if (pipe(pfd1) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pipe(pfd2) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pid == 0) {
        // ------ 子进程 ------
        close(pfd1[1]);
        close(pfd2[0]);
        char buf[1024] = {0};
        int r = 0;
        while (r = read(pfd1[0], buf, sizeof(buf))) {
            if (r > 0) {
                printf("  [child_%ld]:Read %d:%s", getpid(), r, buf);
                if (strcasecmp(buf, "quit\n") == 0) {
                    r = snprintf(buf, sizeof(buf), "Bye Bye.\n");
                    r = write(pfd2[1], buf, r);
                    printf("  [child_%ld]: %ld:%s", getpid(), r, buf);
                    return 0;
                }
                memset(buf, 0, sizeof(buf));
                r = snprintf(buf, sizeof(buf), "250 OK\n");
                r = write(pfd2[1], buf, r);
                printf("  [child_%ld]:Write %ld:%s", getpid(), r, buf);
                memset(buf, 0, sizeof(buf));
            }
        }
        return 0;
    }
    // ------ 父进程 ------
    char buf[1024] = {0};
    int r = 0;
    close(pfd1[0]);
    close(pfd2[1]);
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        printf("[parent_%ld]:Read %d:%s", getpid(), strlen(buf), buf);
        r = write(pfd1[1], buf, strlen(buf));
        printf("[parent_%ld]:Write %d bytes, Succ\n", getpid(), r);
        memset(buf, 0, sizeof(buf));
        r = read(pfd2[0], buf, sizeof(buf));
        printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
        if (strcasecmp(buf, "Bye Bye.\n") == 0) {
            printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
            return 0;
        }
        memset(buf, 0, sizeof(buf));
    }
    return 0;
}


二、连接标准I/O的管道流模式:  子进程使用标准I/O文件描述符进行通讯

    pipe_parent.c:

/*
 * 连接标准I/O的管道流模式: 父子进程互相读写
 * 
 *    --------            -----------------          ---------------
 *   | 父进程 |          |    UNIX 内核    |        | 子进程        |
 *   |        |          |=================|        |               |
 *   | pfd1[1]| -------> |输入  管道I  输出| ------>| 0 <==>pfd1[0] |
 *   |        |          |=================|        |               |
 *   | pfd2[0]| <------- |输出  管道II 输入| <------| 1 <==>pfd2[1] |
 *   |        |          |                 |        |               |
 *    --------            -----------------          ---------------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
char *(pipe_child[]) = { "./pipe_child", 0};
int main(int argc, char **argv)
{
    int pfd1[2], pfd2[2];
    pid_t pid;
    if (pipe(pfd1) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pipe(pfd2) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pid == 0) {
        // ------ 子进程 ------
        if (dup2(pfd1[0], 0) < 0) {
        fprintf(stderr, "child dup2 fail:%s\n", strerror(errno));
        _exit(1);
        }
        if (dup2(pfd2[1], 1) < 0) {
            fprintf(stderr, "child dup2 fail:%s\n", strerror(errno));
            _exit(1);
        }
        close(pfd1[1]);
        close(pfd2[0]);
        int ret = execvp(*pipe_child, pipe_child);
        if (ret < 0) {
            fprintf(stderr, "child execvp:%s fail:%s\n", pipe_child, strerror(errno));
            _exit(1);
        }
        return 0;
    }
    // ------ 父进程 ------
    close(pfd1[0]);
    close(pfd2[1]);
    char buf[1024] = {0};
    int r = 0;
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        printf("[parent_%ld]:Read %d:%s", getpid(), strlen(buf), buf);
        r = write(pfd1[1], buf, strlen(buf));
        printf("[parent_%ld]:Write %d bytes, Succ\n", getpid(), r);
        memset(buf, 0, sizeof(buf));
        r = read(pfd2[0], buf, sizeof(buf));
        printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
        if (strcasecmp(buf, "Bye Bye.\n") == 0) {
            printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
            return 0;
        }
        memset(buf, 0, sizeof(buf));
    }
    return 0;
}


    pipe_child.c:

/*
 * 连接标准I/O的管道流模式: 父子进程互相读写
 * 
 *    --------            -----------------          ---------------
 *   | 父进程 |          |    UNIX 内核    |        | 子进程        |
 *   |        |          |=================|        |               |
 *   | pfd1[1]| -------> |输入  管道I  输出| ------>| 0 <==>pfd1[0] |
 *   |        |          |=================|        |               |
 *   | pfd2[0]| <------- |输出  管道II 输入| <------| 1 <==>pfd2[1] |
 *   |        |          |                 |        |               |
 *    --------            -----------------          ---------------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    char buf[1024] = {0};
    int r = 0;
    while (r = read(0, buf, sizeof(buf))) {
        if (r > 0) {
            fprintf(stderr, "  [child_%ld]:Read %d:%s", getpid(), r, buf);
            if (strcasecmp(buf, "quit\n") == 0) {
                r = snprintf(buf, sizeof(buf), "Bye Bye.\n");
                r = write(1, buf, r);
                fprintf(stderr, "  [child_%ld]: %ld:%s", getpid(), r, buf);
                return 0;
            }
            memset(buf, 0, sizeof(buf));
            r = snprintf(buf, sizeof(buf), "250 OK\n");
            r = write(1, buf, r);
            fprintf(stderr, "  [child_%ld]:Write %ld:%s", getpid(), r, buf);
            memset(buf, 0, sizeof(buf));
        }
    }
    return 0;
}



正确使用 realloc 方法

Publish: September 5, 2016 Category: C/C++ No Comments

1. realloc第一种行为引发的bug

void *ptr = realloc(ptr, new_size);
if (!ptr) {
    错误处理
}

这里就引出了一个内存泄露的问题,当realloc分配失败的时候,会返回NULL。但是参数中的ptr的内存是没有被释放的。如果直接将realloc的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成泄露。


2. 正确的处理应该是这样

void *new_ptr = realloc(ptr, new_size);
if (!new_ptr) {
    错误处理。
}
ptr = new_ptr


C 遍历目录文件

Publish: September 2, 2016 Category: C/C++ No Comments

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>


int trave_dir(char *path)
{
    DIR *pdir;
    struct dirent *pent;
    struct stat sb; 
    if ((pdir = opendir(path)) == NULL) {
        return -1; 
    }   
    
    while ((pent = readdir(pdir)) != NULL) {
        // 去掉(. .. 隐藏文件)
        if (strncmp(pent->d_name, ".", 1) == 0) continue;
    
        char new_path[BUF_SIZE] = {0};
        snprintf(new_path, sizeof(new_path), "%s/%s", path, pent->d_name);
        printf("%s\n", new_path);
        if (stat(new_path, &sb) >= 0 && S_ISDIR(sb.st_mode)) {
            trave_dir(new_path);
        }   
    }   
    closedir(pdir);
    return 0;
}


int main(int argc, char **argv)
{
    trave_dir(argv[1]);

    return 0;
}


编译运行:

# gcc -g -o test test.c
# ./test .


Linux 解决调用函数超时方法

Publish: August 2, 2016 Category: C/C++ No Comments

当我们需要一个别人写的一个函数(可能是库里的),但是该函数可以会执行很长的时间,我们需要对其做超时控制,最简单的方法是使用alarm + signal的处理方式,但是在信号的处理函数中能做的比较少,只能做一些简单的处理,这里提供另外一种方法:

原理:使用线程的 pthread_cond_timedwait() 方法,主线程创建子线程并使用 pthread_cond_timedwait()方法等待,子线程里调用可能超时的函数:

#include <time.h>
#include <pthread.h>
#include <stdio.h>
/* for ETIMEDOUT */
#include <errno.h>
#include <string.h>
pthread_mutex_t calculating = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t done = PTHREAD_COND_INITIALIZER;
void *expensive_call(void *data)
{
        int oldtype;
        /* allow the thread to be killed at any time */
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
        /* ... calculations and expensive io here, for example:
         * infinitely loop
         */
        int i = 0;
        for (;;) {
            printf("%d\n", i); 
            sleep(1);
            i++;
        }   
        /* wake up the caller if we've completed in time */
        pthread_cond_signal(&done);
        return NULL;
}

/* note: this is not thread safe as it uses a global condition/mutex */
int do_or_timeout(struct timespec *max_wait)
{
        struct timespec abs_time;
        pthread_t tid;
        int err;
        pthread_mutex_lock(&calculating);
        /* pthread cond_timedwait expects an absolute time to wait until */
        clock_gettime(CLOCK_REALTIME, &abs_time);
        abs_time.tv_sec += max_wait->tv_sec;
        abs_time.tv_nsec += max_wait->tv_nsec;
        pthread_create(&tid, NULL, expensive_call, NULL);
        /* pthread_cond_timedwait can return spuriously: this should
         * be in a loop for production code
         */
        err = pthread_cond_timedwait(&done, &calculating, &abs_time);
        if (err == ETIMEDOUT)
                fprintf(stderr, "%s: calculation timed out\n", __func__);
        if (!err)
                pthread_mutex_unlock(&calculating);
        return err;
}

int main()
{
        struct timespec max_wait;
        memset(&max_wait, 0, sizeof(max_wait));
        /* wait at most 2 seconds */
        max_wait.tv_sec = 5;
        do_or_timeout(&max_wait);
        printf("Finish\n");
        return 0;
}


编译与执行:

$ gcc -g -o test test.c -pthread -lrt
$ ./test