上一周完成任务不是非常的好,所以总结一下,希望这一周能做好
requirement(代码已补全)
1. 进程实验
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <ctype.h>
#include <stdlib.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_proc_number个子进程要执行
* 父进程把子进程的id保存到pid[i] */
pid_t a = fork();
if(a < 0){
printf("fork error\n");
exit(-1);
}
else if(a == 0){
proc_number = i;
do_something(); //子进程进行任务
}
else{
pid[i] = a; //存储进程id号
}
}
/* 让用户选择杀死进程,数字表示杀死该进程,q退出 */
while ((ch = getchar()) != 'q')
{
if (isdigit(ch))
{
/* 填写代码,向pid[ch-'0']发信号SIGTERM,
* 杀死该子进程 */
kill(pid[ch-'0'],SIGTERM); //向该进程发送kill信号
}
}
/* 在这里写代码,杀死本组的所有进程 */
for(i=0;i<=proc_number;i++){//杀死每个进程
kill(pid[i],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); // 主动阻塞两秒钟
}
}
实验过程
先猜想一下这个程序的运行结果。假如运行“./process 20”,输出会是什么样?
答:只生成十个进程,然后不断循环输出,因为代码定义最大进程数为`0个`
运行程序。开另一个终端窗口,运行“ps aux|grep process”命令,看看process 究竟启动了多少个进
程。回到程序执行窗口,按“数字键+回车”尝试杀掉一两个进程,再到另一个窗口看进程状况。按q 退出程序再看进程情况。
答:创建几个进程就有几个进程,杀死一个进程少一个进程,q退出之后进程都没了,见下图。
回答下列问题
你最初认为运行结果会怎么样?
答:和我想到差不多。
实际的结果什么样?有什么特点?试对产生该现象的原因进行分析。
proc_number 这个全局变量在各个子进程里的值相同吗?为什么?
答:不同,因为在创建进程是我设定了值,具体在代码注释。
kill 命令在程序中使用了几次?每次的作用是什么?执行后的现象是什么?
答:使用了创建进程数2次,之前一次是杀死子进程,最后一次杀死所有进程。
使用kill 命令可以在进程的外部杀死进程。进程怎样能主动退出?这两种退出方式哪种更好一些?
答:杀死进程是使用wait()让主进程等待子进程退出,如果使用kill命令在外部杀死没有在内部杀死好,因为这样进程不是正常结束退出了。生成僵死进程,然后他并不会释放资源
2. 线程实验
/* 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作为参数传递给线程 */
pthread_create(&pthread_id[i],NULL,thread_worker,(void *)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 = (int *)p;
for(;;){
/* 无限循环 */
counter[thread_num]++; /* 本线程的counter加一 */
main_counter++; /* 主counter 加一 */
}
}
实验过程
正确编译程序后,先预计一下这个程序的运行结果。具体的结果会是什么样?运行程序。
开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,
注意查看thread 的CPU 占用率,并记录下这个结果。
答:cpu占有率非常高,而且越来越高,三个死循环太浪费内存了。见下图1
回答下列问题
你最初认为前三列数会相等吗?最后一列斜杠两边的数字是相等,还是大于或者小于关系?
答:结果理应相等,但实际不相等,最后一列小于关系,由于三个进程没有加锁,
互相竞争,所以在竞争的时候,可能一个线程进行main_counter++的时候,被另
一个线程拿到了执行权,去执行了,所以之前线程进行的main_counter++并没有加上去.
见下图2
thread_worker()内是死循环,它是怎么退出的?你认为这样退出好吗?
答:函数内是死循环,所以没有退出,输入q时主进程执行退出,return 退出主线程,
则子线程也强制退出,这样退出不好。
图1
图2
3. 互斥实验
//* POSIX 下线程死锁的演示程序 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#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<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(&mutex2);
pthread_mutex_lock(&mutex1);
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);
}
仔细阅读程序,编译程序后,先预计一下这个程序的运行结果。运行程序。若程序没有响应,按
ctrl+c 中断程序运行,然后再重新运行,如此反复若干次,记录下每次的运行结果。
若产生了死锁,请修改程序,使其不会死锁。
回答下列问题
你预想deadlock.c 的运行结果会如何?
答:打印线程1线程2各执行10000次,但实际结果如下图。
deadlock.c 的实际运行结果如何?多次运行每次的现象都一样吗?为什么会这样?
答:会死锁,而且多次运行,每次死锁的时间都是不一样的,因为线程1和线程2的执行是同时执行
的,所以他会抢占锁的资源,如果出现了线程1获得了锁1,线程2获得了锁2,然后线程1继续进行
还需要获得锁2,线程2进行还需要获得锁1,两个线程就都阻塞在第二个锁哪里。导致了死锁。
解决方法1:使用一个锁即可。解决方法2:互换锁的顺序。示例如下
方法1
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#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<LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex1);
critical_section(1, i);
pthread_mutex_unlock(&mutex1);
}
pthread_mutex_destroy(&mutex1);
return 0;
}
void* thread_worker(void* p)
{
int i;
for (i=0; i<LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex1);
critical_section(2, i);
pthread_mutex_unlock(&mutex1);
}
}
void critical_section(int thread_num, int i){
printf("Thread%d: %d\n", thread_num,i);
}
方法2
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <ctype.h>
#include <pthread.h>
#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<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);
return 0;
}
void* thread_worker(void* p)
{
int i;
for (i=0; i<LOOP_TIMES; i++)
{
pthread_mutex_lock(&mutex1);
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);
}
exam
第一题伪代码写的太丑陋了,就不放出来了,有时间写一个线程池
第二题:聚餐
互斥锁的使用,大概就是五个人每个人左右各有一根筷子,只有左边的筷子和右边的筷子同时处于空闲,才可以使用筷子吃饭,吃饭时间为固定的时间
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <math.h>
pthread_mutex_t chopstick[6] ;
void get(int *left,int *right,char phi) { //通过此函数判断这个人左右是啥筷子
switch (phi){
case 'A':
*left = 5;
*right = 1;
break;
case 'B':
*left = 1;
*right = 2;
break;
case 'C':
*left = 2;
*right = 3;
break;
case 'D':
*left = 3;
*right = 4;
break;
case 'E':
*left = 4;
*right = 5;
break;
}
}
void *eat_think(void *arg)
{
char phi = *(char *)arg;//
int left,right; //
get(&left,&right,phi); //判断是哪一个线程,他的左右筷子分别是啥
for(;;){
usleep(10);
pthread_mutex_lock(&chopstick[left]); //线程先去获取左筷子的锁,如果拿到了继续进行
printf("Philosopher %c fetches chopstick %d\n", phi,left); //打印那个线程拿到左边的锁
if (pthread_mutex_trylock(&chopstick[right]) ==EBUSY){//尝试去拿右边的锁
pthread_mutex_unlock(&chopstick[left]);//没拿到右边的锁就解开左边的锁,不要占用锁的资源
continue;//进行下一轮
}
printf("Philosopher %c fetches chopstick %d\n", phi,right); //打印拿到了右边的锁
printf("Philosopher %c is eating.\n",phi); //打印这个人成功吃饭
usleep(10);
pthread_mutex_unlock(&chopstick[left]); //解开左边的锁
printf("Philosopher %c release chopstick %d\n", phi,left);//打印释放左边的锁
pthread_mutex_unlock(&chopstick[right]);//解开右边的锁
printf("Philosopher %c release chopstick %d\n", phi,right);//打印释放右边的锁
}
}
int main(){
pthread_t A,B,C,D,E; //5个哲学家
int i;
for (i = 0; i < 5; i++)
pthread_mutex_init(&chopstick[i],NULL); //为五个筷子分别创建线程锁
pthread_create(&A,NULL, eat_think, (void *)"A");
pthread_create(&B,NULL, eat_think, (void *)"B");
pthread_create(&C,NULL, eat_think, (void *)"C");
pthread_create(&D,NULL, eat_think, (void *)"D");
pthread_create(&E,NULL, eat_think, (void *)"E");
pthread_join(A,NULL);
pthread_join(B,NULL);
pthread_join(C,NULL);
pthread_join(D,NULL);
pthread_join(E,NULL);
return 0;
}
第三题:生产者消费者问题
我用count++来模拟生产和消费的过程,但是这个当时我在写的时候,我只考虑到了一个线程当做消费者,没有顾忌到多个线程充当消费者,所以只用了一个锁来控制生产者和消费者,没判断消费者的互相竞争
原代码:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int count = 0;
void *a(void *arg){
while(1){
pthread_mutex_lock(&mutex);
count++;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
printf("创建资源的线程A\n");
/* sleep(1); */
if(count > 0){
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
}
void *b(void *arg){
while(1){
pthread_mutex_lock(&mutex);
while(count <= 0){
pthread_cond_wait(&cond,&mutex);
count--;
}
printf("使用资源的线程B\n");
/* sleep(1); */
pthread_mutex_unlock(&mutex);
}
}
int main(){
pthread_t A,B;
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_create(&A,NULL,(void *)a,NULL);
pthread_create(&B,NULL,(void *)b,NULL);
pthread_join(A,NULL);
pthread_join(B,NULL);
return 0;
}
修改后两锁
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
pthread_mutex_t mutex;
pthread_mutex_t mutex2;
pthread_cond_t cond;
int count = 0;
void *a(void *arg){
while(1){
pthread_mutex_lock(&mutex);
count++;
pthread_mutex_unlock(&mutex);
pthread_mutex_lock(&mutex);
printf("创建资源的线程A\n");
/* sleep(1); */
if(count > 0){
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex);
}
}
void *b(void *arg){
while(1){
pthread_mutex_lock(&mutex);
while(count <= 0){
pthread_cond_wait(&cond,&mutex);
pthread_mutex_lock(&mutex2);
count--;
pthread_mutex_unlock(&mutex2);
}
printf("使用资源的线程B\n");
/* sleep(1); */
pthread_mutex_unlock(&mutex);
}
}
int main(){
pthread_t A,B;
pthread_mutex_init(&mutex,NULL);
pthread_mutex_init(&mutex2,NULL);
pthread_cond_init(&cond,NULL);
pthread_create(&A,NULL,(void *)a,NULL);
pthread_create(&B,NULL,(void *)b,NULL);
pthread_join(A,NULL);
pthread_join(B,NULL);
return 0;
}