进程和线程实验总结

看了线程一个礼拜,我觉得最能考验知识就是这次实验题,让我知道了学习中很多的不足
一、进程原题

/*  POSIX 下进程控制的实验程序残缺版 */ 
#include  
#include 
#include  
#include 
#include  
/* 允许建立的子进程个数最大值 */
#define MAX_CHILD_NUMBER 10 
/* 子进程睡眠时间 */
#define SLEEP_INTERVAL 2 
int proc_number=0; 
/* 子进程的自编号,从0开始 */
void do_something(); 

int main(int argc, char* argv[])
{   
    /* 子进程个数 */
    int child_proc_number = MAX_CHILD_NUMBER; 
    int i, ch; 
    pid_t  child_pid; 
    pid_t pid[10]={0}; /* 存放每个子进程的id */ 
    if (argc > 1) /* 命令行参数第一个参数表示子进程个数*/ 
    {
        child_proc_number = atoi(argv[1]); 
        child_proc_number= (child_proc_number > 10) ? 10 :child_proc_number;
    } 
    for (i=0; i/* 填写代码,建立child_proc_number个子进程要执行
        * proc_number = i; 
        * do_something(); 
        * 父进程把子进程的id保存到pid[i] */ 
    }
    /* 让用户选择杀死进程,数字表示杀死该进程,q退出 */
    while ((ch = getchar()) != 'q')  
    { 
        if (isdigit(ch)) 
        { 
            /*  填写代码,向pid[ch-'0']发信号SIGTERM, 
            * 杀死该子进程 */ 
        }
    } 
    /* 在这里填写代码,杀死本组的所有进程 */ 
    return;
} 
void do_something() 
{ 
    for(;;) 
    {  
        printf("This is process No.%d and its pid is %d\n",proc_number,  getpid());
        sleep(SLEEP_INTERVAL); // 主动阻塞两秒钟
    }
}
kill()函数用于删除执行中的程序或者任务。调用格式为: kill(int PID, int IID);
其中:PID是要被杀死的进程号,IID为向将被杀死的进程发送的中断号。

实验过程

先猜想一下这个程序的运行结果。假如运行“./process 20”,输出会是什么样?然后按照注释里的要求把代码补充完整,运行程序。开另一个终端窗口,运行“ps aux|grep process”命令,看看process 究竟启动了多少个进程。回到程序执行窗口,按“数字键+回车”尝试杀掉一两个进程,再到另一个窗口看进程状况。按q 退出程序再看进程情况。

回答下列问题

1、你最初认为运行结果会怎么样?
最开始我觉得应该是num按顺序进行

2、实际的结果什么样?有什么特点?试对产生该现象的原因进行分析。
结果第一次出现了全是0的情况,因为我把父进程进入无限循环,导致只有num0,只要讲子进程进入无线循环就不会有问题了

3、proc_number 这个全局变量在各个子进程里的值相同吗?为什么?
不相同,因为进入子进程,子进程有独立的堆栈,只是复制了一份全局变量

4、kill 命令在程序中使用了几次?每次的作用是什么?执行后的现象是什么?
如果大于等于a.out后面大于等于10,执行10次,每次都会杀死一个子进程,杀死后就不会继续有对应的子进程循环出现

5、使用kill 命令可以在进程的外部杀死进程。进程怎样能主动退出?这两种退出方式哪种更好一些?
进程只要执行结束所有代码,就可以主动退出,这里是杀了所有进程,才可以退出,如果异常退出,使用kill你就会发现很多子进程都变成僵尸进程,因为父进程还没有回收,就已经杀死了
我的改进
#include 
#include 
#include 
#include 
#include 
#include
/* 允许建立的子进程个数最大值 */
#define MAX_CHILD_NUMBER 10
/* 子进程睡眠时间 */
#define SLEEP_INTERVAL 2
int proc_number=0;
/* 子进程的自编号,从0开始 */
void do_something();

int main(int argc, char* argv[])
{
    /* 子进程个数 */
    int child_proc_number = MAX_CHILD_NUMBER;
    int i, ch;
    pid_t  child_pid;
    pid_t pid[10]={0}; /* 存放每个子进程的id */
    if (argc > 1) /* 命令行参数第一个参数表示子进程个数*/
    {
        child_proc_number = atoi(argv[1]);
        child_proc_number= (child_proc_number > 10) ? 10 :child_proc_number;
    }
    pid_t t;
    for (i=0; i/* 填写代码,建立child_proc_number个子进程要执行
        * proc_number = i;
        * do_something();
        * 父进程把子进程的id保存到pid[i] */
        t=fork();
        if(t!=0)
            pid[i]=t;
        if(t==0)//让子进程去执行循环
        {
            proc_number=i;
            do_something();
        }
    }
    /* 让用户选择杀死进程,数字表示杀死该进程,q退出 */
    while ((ch = getchar()) != 'q')
    {
        if (isdigit(ch))
        {
            /*  填写代码,向pid[ch-'0']发信号SIGTERM,
            * 杀死该子进程 */

            kill(pid[ch-'0'],SIGTERM);
            pid[ch-'0']=0;//一定套清零
        }
    }
            kill(0,SIGTERM);//0就是杀死所有进程
    /* 在这里填写代码,杀死本组的所有进程 */
    return 0;
}
void do_something()
{
    for(;;)
    {
        printf("This is process No.%d and its pid is %d\n",proc_number,  getpid());
        sleep(SLEEP_INTERVAL); // 主动阻塞两秒钟
    }
}

二、线程实验(重点!!!)

/*  POSIX 下线程控制的实验程序残缺版 */ 
#include  
#include 
#include  
#include 
#include  

#define MAX_THREAD 3 /* 线程的个数 */
unsigned long long main_counter, counter[MAX_THREAD]; 
/* unsigned long  long是比long还长的整数 */
void* thread_worker(void*); 
int main(int argc,char* argv[])
{     
    int i, rtn, ch;     
    pthread_t pthread_id[MAX_THREAD] = {0}; /* 存放线程id*/ 
    for (i=0; i/* 在这里填写代码,用pthread_create建一个普通的线程,
        线程id存入pthread_id[i],线程执行函数是thread_worker
        并i作为参数传递给线程 */
    }    
    do
    {
        /* 用户按一次回车执行下面的循环体一次。按q退出 */          
        unsigned long long sum = 0;    
        /* 求所有线程的counter的和 */
        for (i=0; i/* 求所有counter的和 */         
            sum += counter[i];             
            printf("%llu ", counter[i]);        
        }
        printf("%llu/%llu", main_counter, sum);   
    }while ((ch = getchar()) != 'q'); 
    return 0;
} 
void* thread_worker(void* p)
{   
    int thread_num;  
    /* 在这里填写代码,把main中的i的值传递给thread_num */ 
    for(;;) 
    { /* 无限循环 */      
     counter[thread_num]++; /* 本线程的counter加一 */ 
     main_counter++; /* 主counter 加一 */   
    } 
}
实验过程 按照注释里的要求把代码补充完整,正确编译程序后,先预计一下这个程序的运行结果。具体的结果会是什么样?运行程序。开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,注意查看thread 的CPU 占用率,并记录下这个结果。

回答下列问题

1、你最初认为前三列数会相等吗?最后一列斜杠两边的数字是相等,还是大于或者小于关系?
刚开始对三者不是特别确定,因为线程比较随意,所以觉得应该不会相等,开始没有运行的时候觉得应该是相等的。

2、最后的结果如你所料吗?有什么特点?对原因进行分析。
最后发现前三个数字,有两个都会是0,斜杠前面的数字还比后面的小
①因为线程是共用的内存地址,i传过去的是地址,所以还没等线程
运行继续,i的值已经变了,所以实际上i值没有很好的传过去。
解决方法可以看下面的改进代码,有三种方法。
②因为线程运行的时候是取出全局变量,但是很多线程取一个全局变量,都会把自己改变的全局变量放回原来的地方,无形之中全局变量就少加了很多,所以为什么有写锁,就是为了防止这种情况的发生

3、thread 的CPU 占用率是多少?为什么会这样?
cpu占有率能达到300%多,因为线程可以多个处理器跑,所有使用也就比较多
4、thread_worker()内是死循环,它是怎么退出的?你认为这样退出好吗?
进程结束之后,所以线程也就完美结束,这样不好,因为没有处理临界资源

完整版
#include
#include 
#include 
#include 
#include 
#include 

#define MAX_THREAD 3 /* 线程的个数 */
unsigned long long main_counter, counter[MAX_THREAD];
/* unsigned long  long是比long还长的整数 */
void* thread_worker(void*);
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
int main(int argc,char* argv[])
{
    int i, rtn, ch;
    int k=0;
    pthread_t pthread_id[MAX_THREAD] = {0}; /* 存放线程id*/
    int *arr;
    for (i=0; iint *)malloc(sizeof(int));
        *arr=i;
        pthread_create(&pthread_id[i],NULL,(void *)thread_worker,arr);
        ②定义一个数组,每次传数组,因为数组每个地址就不一样
        ③从i开刀
         pthread_create(&pthread_id[i],NULL,(void *)thread_worker,(void *)i);//把i的数值强制转换
    }
    do
    {
        char t;
        unsigned long long sum = 0; 
        for (i=0; iprintf("%llu ", counter[i]);
        }
        //注意!!!,这里printf之前全局变量还会在加,所以实际上斜杠左右不一定完全相等
        printf("%llu/%llu", main_counter, sum);//printf的时候maincounter还在++
    }while ((ch = getchar()) != 'q');
    return 0;
}
void* thread_worker(void* p)
{
    int thread_num;
   thread_num=*(int *)p;

    for(;;)
    { 
      pthread_mutex_lock(&mutex1);
     counter[thread_num]++; 
     main_counter++; 
     pthread_mutex_unlock(&mutex1);
    }
}

三、互斥

//* POSIX 下线程死锁的演示程序 */ 
#include  
#include 
#include  
#include 
#include  

#define LOOP_TIMES 10000 

/*用宏PTHREAD_MUTEX_INITIALIZER来初始化 */
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

void* thread_worker(void*);
void critical_section(int thread_num, int i); 

int main(void) 
{     
    int rtn, i;     
    pthread_t pthread_id = 0; /* 存放子线程的id */ 
    rtn = pthread_create(&pthread_id,NULL, thread_worker, NULL ); 
    if(rtn != 0)
    {            
        printf("pthread_create ERROR!\n"); 
        return -1; 
    } 
    for (i=0; i1, i); 
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex1);
    } 

    pthread_mutex_destroy(&mutex1); 
    pthread_mutex_destroy(&mutex2); 
    return 0;
} 
void* thread_worker(void* p) 
{ 
    int i; 
    for (i=0; i2, i); 
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex1);
    }
} 
void critical_section(int thread_num, int i) 
{ 
    printf("Thread%d: %d\n", thread_num,i);
}
仔细阅读程序,编译程序后,先预计一下这个程序的运行结果。运行程序。若程序没有响应,按ctrl+c 中断程序运行,然后再重新运行,如此反复若干次,记录下每次的运行结果。若产生了死锁,请修改程序,使其不会死锁。

回答下列问题
1、你预想deadlock.c 的运行结果会如何?
正常运行
2、deadlock.c 的实际运行结果如何?多次运行每次的现象都一样吗?为什么会这样?
会出现只运行线程一或者只运行线程二,或者交替运行之后卡死,不一样,因为上下线程讲两个变量都锁了,造成死锁
正确版本
//* POSIX 下线程死锁的演示程序 */
#include 
#include 
#include 
#include 
#include 

#define LOOP_TIMES 10000

/*用宏PTHREAD_MUTEX_INITIALIZER来初始化 */
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

void* thread_worker(void*);
void critical_section(int thread_num, int i);

int main(void)
{
    int rtn, i;
    pthread_t pthread_id = 0; /* 存放子线程的id */
    rtn = pthread_create(&pthread_id,NULL, thread_worker, NULL );
    if(rtn != 0)
    {
        printf("pthread_create ERROR!\n");
        return -1;
    }
    for (i=0; i//锁一
        pthread_mutex_lock(&mutex2);
        critical_section(1, i);
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex1);
    }

    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);
    return 0;
}
void* thread_worker(void* p)
{
    int i;
    for (i=0; i//如果这一步锁2,上面的锁要锁2,这时候2已经锁了,于是无线等待
        pthread_mutex_lock(&mutex2);
        critical_section(2, i);
        pthread_mutex_unlock(&mutex2);
        pthread_mutex_unlock(&mutex1);
    }
}
void critical_section(int thread_num, int i)
{
    printf("Thread%d: %d\n", thread_num,i);
} 

你可能感兴趣的:(Linux)