实验1 进程

1.目的

通过观察、分析实验现象,深入理解进程及进程在调度执行和内存空间等方面的特点,掌握在POSIX 规范中fork和kill系统调用的功能和使用。 

实验前准备

  学习man 命令的用法,通过它查看fork 和kill 系统调用的在线帮助,并阅读参考资料,学会fork 与kill 的用法。复习C 语言的相关内容。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h> 
#include <signal.h>
#include <ctype.h> 
/* 允许建立的子进程个数最大值 */
#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; i++) 
     { 
    child_pid=fork();
        if(child_pid!=0)
    {
        pid[i]=child_pid;
    }
     else
     {
    /* 填写代码,建立child_proc_number个子进程要执行
     * proc_number = i; 
     * do_something(); 
     * 父进程把子进程的id保存到pid[i] 
     * */ 
        proc_number=i;
        do_something();
     }
}
      /* 让用户选择杀死进程,数字表示杀死该进程,q退出 */
      while ((ch = getchar()) != 'q')     
     { 
            if (isdigit(ch))  
            { 
             /*  填写代码,向pid[ch-'0']发信号SIGTERM,*杀死该子进程 */ 
             kill(pid[ch-'0'],SIGTERM);
           }
      } 
      /* 在这里填写代码,杀死本组的所有进程 */ 
        kill(0,SIGTERM);
    return 0;
} 

void do_something() 
{ 
     for(;;)  
     {  
      printf("This is process No.%d and its pid is %d\n", proc_number,  getpid());
      sleep(SLEEP_INTERVAL); /* 主动阻塞两秒钟 */  
     } 
}

运行情况:

zach@zach-i16:~/文档/os$ ./process 3
This is process No.2 and its pid is 3540
This is process No.1 and its pid is 3539
This is process No.0 and its pid is 3538
This is process No.1 and its pid is 3539
This is process No.0 and its pid is 3538
This is process No.2 and its pid is 3540
1
This is process No.0 and its pid is 3538
This is process No.2 and its pid is 3540
2
This is process No.0 and its pid is 3538
3
已终止

kill()函数用于删除执行中的程序或者任务。调用格式为:
kill(int PID, int IID);
其中:PID是要被杀死的进程号,IID为向将被杀死的进程发送的中断号.

实验3 线程

目的

 通过观察、分析实验现象,深入理解线程及线程在调度执行和内存空间等方面的特点,并掌握线程与进程的区别。掌握POSIX 规范中pthread_create() 函数的功能和使用方法。 

实验前准备

 阅读参考资料,了解线程的创建等相关系统调用。 
/*  POSIX 下线程控制的实验程序残缺版 */ 
#include <stdio.h> 
#include <sys/types.h>
#include <unistd.h> 
#include <ctype.h>
#include <pthread.h> 

#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<MAX_THREAD; i++)
      {          
          /* 在这里填写代码,用pthread_create建一个普通的线程,线程id存入pthread_id[i],线程执行函数是thread_worker并i作为参数传递给线程 */
          rtn=pthread_create(& pthread_id[i],NULL,(void *)thread_worker,i);     
      }      
       do 
       {
        /* 用户按一次回车执行下面的循环体一次。按q退出 */
         unsigned long long sum = 0;         
         /* 求所有线程的counter的和 */
         for (i=0; i<MAX_THREAD; 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 */
    thread_num=p; 
    for(;;) 
     {    
         /* 无限循环 */ 
          counter[thread_num]++; /* 本线程的counter加一*/ 
          main_counter++; /* 主counter 加一 */    
      }  
}

运行情况

zach@zach-i16:~/文档/os$ ./process3
0 3439 0 3781/3439
147825977 173501711 76050439 278869308/397378126
425287134 219440108 121358850 536654323/766086076
640152823 368891179 198391806 847618905/1207435792
738229522 599211834 248175335 1113963652/1585616684
968491690 636516600 286022645 1327432250/1891030934q

可以从运行情况看出main_counter(总的循环次数)和sum(3个线程各自循环次数的总和)值不相等,但理论上两个数的值应该是相等的.

因为假设main_counter=0时,当线程1还没有完成加1操作的时候,main_counter还是为0此时线程2也开始执行main_counter++,两线程各执行一次加1操作,线程1将main_counter值变为1,线程2也将main_的值变为1,导致main_counter实际只加了1,比理论值偏小.

为了解决这一问题,给输出的时候加锁:

#include <stdio.h> 
#include <sys/types.h>
#include <unistd.h> 
#include <ctype.h>
#include <pthread.h> 

#define MAX_THREAD 3 /* 线程的个数 */
unsigned long long main_counter, counter[MAX_THREAD]; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* 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<MAX_THREAD; i++)       
      {        
        rtn=pthread_create(&pthread_id[i],NULL,(void *)thread_worker,i);
      }     
       do {
           pthread_mutex_lock(&mutex);
                   unsigned long long sum = 0;    
           for (i=0; i<MAX_THREAD; i++) 
          {                 
                sum += counter[i];              
                    printf("%llu ", counter[i]);
          }  
           printf("%llu/%llu", main_counter, sum);
               pthread_mutex_unlock(&mutex);   
           }  while ((ch = getchar()) != 'q');
    pthread_mutex_destroy(&mutex);
    return 0;  
}               
 void* thread_worker(void* p)
 {      
     int thread_num;  
     thread_num=p;
     /* 在这里填写代码,把main中的i的值传递给thread_num */ 

     for(;;)
      { /* 无限循环 */
          pthread_mutex_lock(&mutex);       
          counter[thread_num]++; /* 本线程的counter加一 */ 
          main_counter++; /* 主counter 加一 */
          pthread_mutex_unlock(&mutex);   
      }
 }      

执行情况:

zach@zach-i16:~/文档/os$ ./process3
466 0 0 466/466
2470436 2513089 2641403 7624928/7624928
4676030 5015065 5015462 14706557/14706557
7866636 8291442 8161852 24319930/24319930
12619489 12585861 12681943 37887293/37887293
13956112 13899913 14071728 41927753/41927753
16308110 15997805 16218050 48523965/48523965
16980084 16692473 16886541 50559098/50559098q

注意因为pthread库不是Linux系统默认的库,所以编译时应该连接库函数

gcc process3.c -l pthread -o process3

实验4 互斥

目的

   通过观察、分析实验现象,深入理解理解互斥锁的原理及特点掌握在POSIX 规范中的互斥函数的功能及使用方法。 

实验前准备

准备好上节实验完成的程序thread.c 。
阅读参考资料,了解互斥锁的加解锁机制及相关的系统调用。

实验内容

//* POSIX 下线程死锁的演示程序 */ 
#include <stdio.h> 
#include <sys/types.h>
#include <unistd.h> 
#include <ctype.h>
#include <pthread.h> 
#define LOOP_TIMES 10000 
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
           /*用宏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<LOOP_TIMES; i++)  
      {            
         pthread_mutex_lock(&mutex1);   
         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<LOOP_TIMES; i++)
      { 
        pthread_mutex_lock(&mutex1);//本来是先2后1,这里锁的顺序变一下,变为先1后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);
}
Logo

更多推荐