C语言实现用户态计算线程切换时间和进程切换时间

本文通过C++代码示例,详细分析了父子进程间利用管道进行100次切换的时间计算,以及线程间利用信号量实现的同步切换。讨论了进程间同步的实现,如管道、信号量和文件,以及线程间同步的信号量机制。文章还展示了如何测量进程和线程切换的时间,并提供了实际的性能数据。
摘要由CSDN通过智能技术生成

计算进程切换,此文章主要计算的是父子进程间切换100次的时间,父子进程间用管道pipe进行通信,父进程先写管道,然后进入读阻塞,子进程先进入读阻塞,然后再写管道;用管道实现父子进程的同步功能(即父进程先运行结束以后等待子进程,接着子进程运行结束以后等待父进程,父进程再运行结束以后等待子进程,子进程再运行结束以后等待父进程……如此循环往复)。实现进程间(有亲缘关系)同步,除了管道并且没有亲缘关系的进程也可以通过信号量和文件来实现,这两种方法就略略了(主要还是心懒了,感兴趣的可以随时联系一起实现,毕竟人多了有动力有心情,1+1>2)。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <strings.h>
#include <string.h>
#include <errno.h>

#define CIRCULCNT 100
#define CUNCHULEN CIRCULCNT*2

int cunchu[CUNCHULEN];

struct sendmes
{
    int diffusec;
    struct timeval tv1;
};

int main()
{
    pid_t pid;
    int fd1[2];
    int fd2[2];
    int ret,l;
    for(l=0;l<CUNCHULEN;l++)
    {
        cunchu[l]=-1;
    }
    /*创建管道*/
    ret=pipe(fd1);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }
    /*创建管道*/
    ret=pipe(fd2);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }
    pid=fork();
    if(pid==0)
    {
        int i=0;
        struct timeval tv1;
        struct timeval tv2;
        struct sendmes mymes;
        int difftime;
        close(fd1[1]);
        close(fd2[0]);
        /*semid=semget((key_t)1234 ,1, IPC_CREAT|0666);
        struct sembuf sem_b;*/
        for(i=0;i<CIRCULCNT;i++)
        {
            /*bzero(&sem_b,sizeof(struct sembuf));
            sem_b.sem_num=0;
            sem_b.sem_op=-1;
            sem_b.sem_flg=SEM_UNDO;
            semop(sem_id,&sem_b,1);*/

            /*读管道信息,并把父进程发送过来的时间读出来*/
            bzero(&mymes,sizeof(struct sendmes));
            read(fd1[0],&mymes,sizeof(struct sendmes));
            
            bzero(&tv1,sizeof(struct timeval));
            /*获取当前时间*/
            gettimeofday(&tv1,NULL);
            /*当前时间-父进程要切换的时间得出进程切换的时间,以微妙计时*/
            //printf("father to son:%ld usec\n",1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec);
            difftime=(int)(1000000*(tv1.tv_sec-mymes.tv1.tv_sec)+tv1.tv_usec-mymes.tv1.tv_usec);

            bzero(&mymes,sizeof(struct sendmes));
            mymes.diffusec=difftime;
            /*获取当前时间,并且发送给父进程*/
            gettimeofday(&(mymes.tv1),NULL);
            write(fd2[1],&mymes,sizeof(struct sendmes));
            /*bzero(&sem_b,sizeof(struct sembuf));
            sem_b.sem_num=0;
            sem_b.sem_op=1;
            sem_b.sem_flg=SEM_UNDO;
            semop(sem_id,&sem_b,1);*/
        }
        close(fd1[0]);
        close(fd2[1]);
        return 0;
    }
    else
    {
        int i=0,j;
        struct timeval tv1;
        struct timeval tv2;
        struct sendmes mymes;
        close(fd1[0]);
        close(fd2[1]);
        for(i=0;i<CIRCULCNT;i++)
        {
            /*获取当前管道时间,并把管道时间传送给子进程*/
            bzero(&mymes,sizeof(struct sendmes));
            gettimeofday(&(mymes.tv1),NULL);
            write(fd1[1],&mymes,sizeof(struct sendmes));
            //printf("mymes.tv1.tv_sec=%ld,mymes.tv1.tv_usec=%ld\n",mymes.tv1.tv_sec,mymes.tv1.tv_usec);

            /*读取子进程的要切换之前的时间*/
            bzero(&mymes,sizeof(struct sendmes));
            read(fd2[0],&mymes,sizeof(struct sendmes));

            /*当前时间-子进程的要切换之前的时间得出切换时间*/
            bzero(&tv2,sizeof(struct timeval));
            gettimeofday(&tv2,NULL);
            //printf("son to father:%ld usec\n",1000000*(tv2.tv_sec-mymes.tv1.tv_sec)+tv2.tv_usec-mymes.tv1.tv_usec);    
            for(j=0;j<CUNCHULEN;j++)
            {
                if(cunchu[j]==-1)
                {
                    cunchu[j]=mymes.diffusec;
                    break;
                }
                
            }
            for(j=0;j<CUNCHULEN;j++)
            {
                if(cunchu[j]==-1)
                {
                    cunchu[j]=(int)(1000000*(tv2.tv_sec-mymes.tv1.tv_sec)+tv2.tv_usec-mymes.tv1.tv_usec);
                    break;
                }
                
            }
        }
        close(fd1[1]);
        close(fd2[0]);
    }
    int j;
    int maxusec=0;
    int totalusec=0;
    int minusec;
    int secflag=0;
    int cnt=0;
    for(j=0;j<CUNCHULEN;j++)
    {
        if(-1==cunchu[j])
            continue;
        if(secflag==0)
            minusec=cunchu[j];
        secflag=1;
        totalusec+=cunchu[j];
        if(minusec>cunchu[j])
            minusec=cunchu[j];
        if(maxusec<cunchu[j])
            maxusec=cunchu[j];
        cnt++;
        //printf("%d\n",cunchu[j]);
    }
    printf("cnt=%d\n",cnt);
    printf("max:[%d]usec\tmin:[%d]usec\taverage:[%d]usec\n",maxusec,minusec,totalusec/cnt);
    
    return 0;
}

 线程间切换,线程切换就比进程切换容易多了,因为多个线程都是在同一个资源多种,可以实现资多线程源共享,这里用的信号量来同步多线程(同步即线程A执行完以后线程B执行,线程B执行完以后线程A执行……如此循环往复)。注意线程间同步的信号函数与进程间同步所用到的信号量函数可不一样,但是原理是一样的。

#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <semaphore.h>
#include <sys/time.h>

#define CIRCULCNT 100
#define CUNCHULEN CIRCULCNT*2

sem_t sem1;
sem_t sem2;
struct timeval tv1;
struct timeval tv2;
int cunchu[CUNCHULEN];

void *func1(void *arg)
{
    int i,j;
    for(i=0;i<CIRCULCNT;i++)
    {
        /*给sem1加锁*/
        sem_wait(&sem1);
        bzero(&tv1,sizeof(struct timeval));
        /*获取当前时间*/
        gettimeofday(&tv1,NULL);
        /*打印线程切换时间*/
        if(i!=0)
        {
            //printf("func2 to func1:%ld usec\n",1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec);
            for(j=0;j<CUNCHULEN;j++)
            {
                if(cunchu[j]==-1)
                {
                    cunchu[j]=(int)(1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec);
                    break;
                }
            }
        }
        bzero(&tv1,sizeof(struct timeval));
        /*获取当前时间*/
        gettimeofday(&tv1,NULL);
        /*给sem2解锁*/
        sem_post(&sem2);
    }
    
    return NULL;
}

void *func2(void *arg)
{
    int i,j;
    for(i=0;i<CIRCULCNT;i++)
    {
        /*给sem2加锁*/
        sem_wait(&sem2);
        bzero(&tv2,sizeof(struct timeval));
        /*获取当前时间*/
        gettimeofday(&tv2,NULL);
        /*打印线程切换时间*/
            //printf("func2 to func1:%ld usec\n",1000000*(tv1.tv_sec-tv2.tv_sec)+tv1.tv_usec-tv2.tv_usec);
        for(j=0;j<CUNCHULEN;j++)
        {            
            if(cunchu[j]==-1)
            {
                cunchu[j]=(int)(1000000*(tv2.tv_sec-tv1.tv_sec)+tv2.tv_usec-tv1.tv_usec);
                break;
            }
        }
        //printf("func1 to func2:%ld usec\n",1000000*(tv2.tv_sec-tv1.tv_sec)+tv2.tv_usec-tv1.tv_usec);
        bzero(&tv2,sizeof(struct timeval));
        /*获取当前时间*/
        gettimeofday(&tv2,NULL);
        /*给sem1解锁*/
        sem_post(&sem1);
    }

    return NULL;
}

int main()
{
    pthread_t pth1;
    pthread_t pth2;
    int ret;
    int i;
    for(i=0;i<CUNCHULEN;i++)
    {
        cunchu[i]=-1;
    }
    bzero(&tv1,sizeof(struct timeval));
    bzero(&tv2,sizeof(struct timeval));
    /*初始化信号量sem1*/
    ret=sem_init(&sem1,0,1);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }
    /*初始化信号量sem2*/
    ret=sem_init(&sem2,0,0);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }

    /*创建线程pth1*/
    ret=pthread_create(&pth1,NULL,func1,NULL);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }
    /*创建线程pth2*/
    ret=pthread_create(&pth2,NULL,func2,NULL);
    if(ret!=0)
    {
        printf("%s[%d]:%d %s\n",__FUNCTION__,__LINE__,errno,strerror(errno));
        return -1;
    }

    /*等待线程pth1*/
    pthread_join(pth1,NULL);
    /*等待线程pth2*/
    pthread_join(pth2,NULL);

    /*销毁信号量sem1*/
    sem_destroy(&sem1);
    /*销毁信号量sem2*/
    sem_destroy(&sem2);
    int maxusec=0;
    int minusec=0;
    int cnt=0;
    int totalusec=0;
    int flag=0;
    for(i=0;i<CUNCHULEN;i++)
    {
        if(cunchu[i]==-1)
            continue;
        if(flag==0)
            minusec=cunchu[i];
        totalusec+=cunchu[i];
        if(maxusec<cunchu[i])
        {
            maxusec=cunchu[i];
        }
        if(minusec>cunchu[i])
        {
            minusec=cunchu[i];
        }
        cnt++;
        flag=1;
        //printf("%d\n",cunchu[i]);
    }
    printf("cnt=%d\n",cnt);
    printf("max:[%d]usec\tmin:[%d]usec\taverage:[%d]usec\n",maxusec,minusec,totalusec/cnt);
    return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值