1.编程实现互斥机制
程序代码:
1 #include<myhead.h>
2 int num=520;//临界资源
3 //1.创建一个互斥锁变量
4 pthread_mutex_t mutex;//定义一个pthread_mutex_t类型的变量
5 //定义任务1函数
6 void *task1(void *arg)
7 {
8 printf("不畏过去\n");
9 //获取锁资源
10 pthread_mutex_lock(&mutex);//互斥锁地址
11 num=1314;
12 sleep(3);
13 printf("task1:num=%d\n",num);
14 //释放锁资源
15 pthread_mutex_unlock(&mutex);//互斥锁地址
16 }
17 //定义任务2函数
18 void *task2(void *arg)
19 {
20 printf("不惧将来\n");
21 //获取锁资源
22 pthread_mutex_lock(&mutex);
23 num++; //521
24 sleep(1); //休眠,执行任务一的赋值语句num=1314
25 //遇到任务1中的互斥锁,回到这等休眠结束,执行任务二所有程序
26 printf("task2:num=%d\n",num);
27 //释放锁资源
28 pthread_mutex_unlock(&mutex);
29 //释放完再回到任务一的互斥锁位置,执行任务一所以程序
30 }
31 int main(int argc, const char *argv[])
32 {
33 //2.初始化互斥锁
34 pthread_mutex_init(&mutex,NULL);//互斥锁地址,互斥锁属性,成败返回0
35 //创建两个线程
36 pthread_t tid1,tid2;//线程号变量
37 if(pthread_create(&tid1,NULL,task1,NULL)!=0)
38 //创建分支线程,成0败错误码(不是置位错误码)
39 //线程号指针,线程属性,线程体(函数指针),线程体的参数
40 {
41 printf("tid1 create error\n");//是POSIX库错误码,不能用ferror()
42 return 0;
43 }
44 if(pthread_create(&tid2,NULL,task2,NULL)!=0)
45 {
46 printf("tid2 create error\n");
47 return 0;
48 }
49 printf("tid1:%#lx,tid2:%#lx\n",tid1,tid2);//线程号
50 //回收线程资源
51 pthread_join(tid1,NULL);//阻塞等待指定线程的退出,收尸,成0败错误码
52 pthread_join(tid2,NULL);//要回收的线程号,要回收的线程退出时的状态,NULL
53 //销毁锁资源
54 pthread_mutex_destroy(&mutex);//互斥锁指针
55 return 0;
56 }
运行结果:
2.编程实现无名信号量
(1)生产和销售
程序代码:
1 #include<myhead.h>
2 //1.创建无名信号量
3 sem_t sem;//定义一个sem_t类型的变量
4 //定义生产线程
5 void *task1(void *arg)
6 {
7 int num=5;//定义循环量
8 while(num--)
9 {
10 sleep(1);
11 printf("生产三蹦子\n");
12 //4.释放资源
13 sem_post(&sem);//释放无名信号量资源,value加1,
14 //无名信号量地址
15 }
16 //退出线程
17 pthread_exit(NULL);//线程退出时状态,NULL
18 }
19 //定义消费线程
20 void *task2(void *arg)
21 {
22 int num=5;
23 while(num--)
24 {
25 //3.申请资源
26 sem_wait(&sem);//申请资源,value减1,为0时阻塞,无名信号量地址
27 printf("消费三蹦子\n");
28 }
29 pthread_exit(NULL);
30 }
31 int main(int argc, const char *argv[])
32 {
33 //2.初始化无名信号量
34 sem_init(&sem,0,0);
35 //无名信号量地址,0线程间同步,当前无名信号量维护的value值初始值
36 //创建两个线程,生产和消费
37 pthread_t tid1,tid2;
38 if(pthread_create(&tid1,NULL,task1,NULL)!=0)
39 //线程号指针,线程属性,线程体(函数体),线程体的参数
40 //成0败POSIX库中错误码,不能perror()
41 {
42 printf("tid1 create error\n");
43 return 0;
44 }
45 if(pthread_create(&tid2,NULL,task2,NULL)!=0)
46 {
47 printf("tid2 create error\n");
48 return 0;
49 }
50 printf("tid1:%#lx,tid2:%#lx\n",tid1,tid2);
51 //回收线程资源
52 pthread_join(tid1,NULL);//阻塞等待指定线程退出,收尸
53 pthread_join(tid2,NULL);//要回收的线程号、要回收线程退出时状态
54 //释放无名信号量
55 sem_destroy(&sem);//无名信号量地址
56 return 0;
57 }
运行结果:
(2)创建三个线程,线程1打印A,线程2打印B,线程3打印C
程序代码:
1 #include<myhead.h>
2 //创建无名信号量
3 sem_t sem1,sem2,sem3;
4 //定义线程1
5 void *task1(void *arg)
6 {
7 int num=3;
8 while(num--)
9 {
10 //3.申请资源
11 sem_wait(&sem1);
12 sleep(1);
13 printf("A\t");
14 //刷新给定文件指针缓冲区,要刷新的缓冲区
15 //stdout标准输出指针
16 fflush(stdout);
17 //4.释放资源
18 sem_post(&sem2);//释放无名信号量sem2的资源,value加1
19 }
20 //退出线程
21 pthread_exit(NULL);
22 }
23 //定义线程2
24 void *task2(void *arg)
25 {
26 int num=3;
27 while(num--)
28 {
29 sem_wait(&sem2);//sem2资源-1
30 sleep(1);
31 printf("B\t");
32 fflush(stdout);//输出没有\n,不刷新不会打印出来,等全部运行结束直接给出结果
33 sem_post(&sem3);//sem3资源+1,sem3才能接着用
34 }
35 pthread_exit(NULL);
36 }
37 //定义线程3
38 void *task3(void *arg)
39 {
40 int num=3;
41 while(num--)
42 {
43 //申请资源sem3
44 sem_wait(&sem3);
45 sleep(1);
46 printf("C\t");
47 fflush(stdout);
48 sem_post(&sem1);//释放sem1资源,
49 }
50 pthread_exit(NULL);
51 }
52 int main(int argc, const char *argv[])
53 {
54 //初始化无名信号量
55 sem_init(&sem1,0,1);//无名信号量地址
56 sem_init(&sem2,0,0);//0线程同步
57 sem_init(&sem3,0,0);//初始资源为1,0
58 //定义线程号变量
59 pthread_t tid1,tid2,tid3;
60 if(pthread_create(&tid1,NULL,task1,NULL)!=0)//创建线程分支
61 {
62 printf("tid1 create error\n");
63 return 0;
64 }
65 if(pthread_create(&tid2,NULL,task2,NULL)!=0)//无名信号量地址,线程属性,线程体,线程体参数
66 {
67 printf("tid2 create error\n");
68 return 0;
69 }
70 if(pthread_create(&tid3,NULL,task3,NULL)!=0)
71 {
72 printf("tid3 create error\n");
73 return 0;
74 }
75 printf("tid1:%#lx,tid2:%#lx,tid3:%#lx\n",tid1,tid2,tid3);
76 //回收线程资源
77 pthread_join(tid1,NULL);
78 pthread_join(tid2,NULL);
79 pthread_join(tid3,NULL);
80 //释放无名信号量
81 sem_destroy(&sem1);
82 sem_destroy(&sem2);
83 sem_destroy(&sem3);
84 puts("");
85 return 0;
86 }
运行结果:
3.编程实现条件变量
程序代码:
1 #include<myhead.h>
2 //1.定义条件变量
3 pthread_cond_t cond;
4 //定义互斥锁变量
5 pthread_mutex_t mutex;
6 //定义生产线程
7 void *task1(void *arg)
8 {
9 int num=5;
10 while(num--)
11 {
12 sleep(1);
13 printf("%#lx:生产三蹦子\n",pthread_self());
14 //3.唤醒一个消费
15 // pthread_cond_signal(&cond);//条件变量地址
16 }
17 //3.唤醒所以的等待线程
18 pthread_cond_broadcast(&cond);//条件变量地址
19 //退出线程
20 pthread_exit(NULL);
21 }
22 //定义消费线程
23 void *task2(void *arg)
24 {
25 //上锁
26 pthread_mutex_lock(&mutex);
27 //进入等待队列
28 pthread_cond_wait(&cond,&mutex);//条件变量指针,互斥锁变量地址
29 //该函数内部实现
30 //将当前线程放入休眠等待队列,释放锁资源
31 //挂起,被其他线程唤醒后:自动获取锁资源
32 printf("%#lx:消费三蹦子\n",pthread_self());
33 //解锁
34 pthread_mutex_unlock(&mutex);
35 pthread_exit(NULL);
36 }
37 int main(int argc, const char *argv[])
38 {
39 //2.初始化条件变量
40 pthread_cond_init(&cond,NULL);//条件变量指针,条件属性
41 //初始化互斥锁
42 pthread_mutex_init(&mutex,NULL);//互斥锁变量地址,互斥锁属性
43 //创建两个线程,生产和消费
44 pthread_t tid1,tid2,tid3,tid4,tid5,tid6;
45 if(pthread_create(&tid1,NULL,task1,NULL)!=0)//线程号指针
46 {
47 printf("tid1 create error\n");//成0败非0错误码,不是置位错误码
48 return 0;
49 }
50 if(pthread_create(&tid2,NULL,task2,NULL)!=0)//线程属性
51 {
52 printf("tid2 create error\n");
53 return 0;
54 }
55 if(pthread_create(&tid3,NULL,task2,NULL)!=0)//线程体,函数指针
56 {
57 printf("tid3 create error\n");
58 return 0;
59 }
60 if(pthread_create(&tid4,NULL,task2,NULL)!=0)//线程体的参数
61 {
62 printf("tid4 create error\n");
63 return 0;
64 }
65 if(pthread_create(&tid5,NULL,task2,NULL)!=0)
66 {
67 printf("tid5 create error\n");
68 return 0;
69 }
70 if(pthread_create(&tid6,NULL,task2,NULL)!=0)
71 {
72 printf("tid6 create error\n");
73 return 0;
74 }
75 printf("tid1:%#lx,tid2:%#lx,tid3:%#lx,tid4:%#lx,tid5:%#lx,\
76 tid6:%#lx\n",tid1,tid2,tid3,tid4,tid5,tid6);
77 //回收线程资源
78 pthread_join(tid1,NULL);//线程号,线程回收时状态
79 pthread_join(tid2,NULL);
80 pthread_join(tid3,NULL);
81 pthread_join(tid4,NULL);
82 pthread_join(tid5,NULL);
83 pthread_join(tid6,NULL);
84 //销毁条件变量
85 pthread_cond_destroy(&cond);//条件变量指针
86 //销毁互斥锁
87 pthread_mutex_destroy(&mutex);//无名信号量地址
88 return 0;
89 }
运行结果:
4.编程实现无名管道
程序代码:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //创建管道文件,并返回该管道文件的文件描述符
5 int pipefd[2]={0};//返回pipefd[0]读端,pipefd[1]写端
6 if(pipe(pipefd)==-1)
7 {
8 perror("pipe error");
9 return -1;
10 }
11 printf("pipe[0]=%d,pipe[1]=%d\n",pipefd[0],pipefd[1]);
12 //创建子进程
13 pid_t pid=fork();
14 if(pid>0)
15 {
16 //父进程
17 //关闭管道读端
18 //创建管道文件放在创建子进程之前,否则各自创建一个管道,无意义
19 //父进程、子进程都创建同一个管道描述符,
20 //要关闭父进程的读端,子进程的写端
21 close(pipefd[0]);//pipefd[0] 读
22 char wbuf[128]="";
23 while(1)
24 {
25 bzero(wbuf,sizeof(wbuf));//清空数组内容,
26 //每次写入不同长度,写短了就会保留长的一部分
27 fgets(wbuf,sizeof(wbuf),stdin);//终端输入数据
28 wbuf[strlen(wbuf)-1]=0;//把读取的字符串,最后一个改为0,便于比较
29 //将数据写入管道文件
30 write(pipefd[1],wbuf,strlen(wbuf));//要操作的文件描述符,容器起始位置,读取大小
31 //对写入数据判断
32 if(strcmp(wbuf,"quit")==0)
33 break;
34 }
35 //关闭写端
36 close(pipefd[1]);
37 wait(NULL);//阻塞回收子进程资源
38 }else if(pid==0)
39 {
40 //子进程
41 //关闭写端
42 close(pipefd[1]);
43 char rbuf[128]="";
44 while(1)
45 {
46 //清空rbuf内容
47 bzero(rbuf,sizeof(rbuf));
48 //从管道文件中读取数据
49 read(pipefd[0],rbuf,sizeof(rbuf));
50 //输出rbuf的数据
51 printf("父进程传来数据:%s\n",rbuf);
52 //对读取的数据判断
53 if(strcmp(rbuf,"quit")==0)
54 break;
55 }
56 //关闭读端
57 close(pipefd[0]);
58 exit(EXIT_SUCCESS);//退出进程
59 }else
60 {
61 perror("fork error");
62 return -1;
63 }
64 return 0;
65 }
运行结果:
5.编程实现有名管道
程序代码:
create.c:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //创建一个管道文件
5 if(mkfifo("./myfifo",0664)==-1)
6 {
7 perror("mkfifo error");
8 return -1;
9 }
10 getchar();//阻塞
11 system("rm myfifo");
12
13 return 0;
14 }
send.c:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //打开管道文件
5 int wfd=-1;
6 //以只写形式打开
7 if((wfd=open("./myfifo",O_WRONLY))=
8 {
9 perror("open error");
10 return -1;
11 }
12 //定义容器
13 char wbuf[128]="";
14 while(1)
15 {
16 printf("请输入>>>");
17 fgets(wbuf,sizeof(wbuf),stdin);
18 wbuf[strlen(wbuf)-1]=0;
19 //将数据写入管道
20 write(wfd,wbuf,strlen(wbuf));
21 //判断结果
22 if(strcmp(wbuf,"quit")==0)
23 break;
24 }
25 //关闭文件
26 close(wfd);
27 return 0;
28 }
rec.c:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //打开管道文件
5 int rfd=-1;
6 //以只读形式打开
7 if((rfd=open("./myfifo",O_RDONLY))=
8 {
9 perror("open error");
10 return -1;
11 }
12 //定义容器
13 char rbuf[128]="";
14 while(1)
15 {
16 //清空数组
17 bzero(rbuf,sizeof(rbuf));
18 //读取管道中数据
19 read(rfd,rbuf,sizeof(rbuf));
20 //输出结果
21 printf("收到数据:%s\n",rbuf);
22 if(strcmp(rbuf,"quit")==0)
23 break;
24 }
25 //关闭文件
26 close(rfd);
27 return 0;
28 }
运行结果:
6.使用有名管道完成两个进程的相互通信
程序代码:
01create:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //创建两个管道文件
5 if(mkfifo("./myfifo1",0664)==-1)
6 {
7 perror("myfifo1 create error");
8 return -1;
9 }
10 if(mkfifo("./myfifo2",0664)==-1)
11 {
12 perror("myfifo2 create error");
13 return -1;
14 }
15 printf("create success\n");
16 getchar();//阻塞进程
17 system("rm myfifo1 myfifo2");//删除两>
18 return 0;
19 }
01send.c:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //两个进程,父进程给管道1写数据,子进程从管道2读取数据
5 pid_t pid=-1;
6 pid=fork();
7 if(pid==0)
8 {
9 //子进程管道2读取数据
10 int rfd=-1;
11 if((rfd=open("./myfifo2",O_RDONLY))==-1)
12 {
13 perror("open myfifo2 error");
14 return -1;
15 }
16 char buf[128]="";
17 while(1)
18 {
19 bzero(buf,sizeof(buf));//清空数组
20 read(rfd,buf,sizeof(buf));//从管道2读取数据
21 printf("读取数据:%s\n",buf);
22 if(strcmp(buf,"quit")==0)
23 break;
24 }
25 //关闭文件
26 close(rfd);
27 //退出进程
28 exit(EXIT_SUCCESS);
29 }else if(pid>0)
30 {
31 //父进程向管道1写数据
32 int wfd=-1;
33 if((wfd=open("./myfifo1",O_WRONLY))==-1)
34 {
35 perror("open myfifo1 error");
36 return -1;
37 }
38 char buf[128]="";
39 while(1)
40 {
41 bzero(buf,sizeof(buf));//清空数组
42 fgets(buf,sizeof(buf),stdin);
43 buf[strlen(buf)-1]=0;
44 //将数据写入管道
45 write(wfd,buf,strlen(buf));
46 if(strcmp(buf,"quit")==0)
47 break;
48 }
49 //关闭文件
50 close(wfd);
51 //回收子进程资源
52 wait(NULL);
53 }else
54 {
55 perror("fork error");
56 return -1;
57 }
58 return 0;
59 }
02send.c:
1 #include<myhead.h>
2 int main(int argc, const char *argv[])
3 {
4 //两个进程,父进程读取管道1数据,子进程写数据给管道2
5 pid_t pid=-1;
6 pid=fork();
7 if(pid<0)
8 {
9 perror("fork error");
10 return -1;
11 }else if(pid==0)
12 {
13 //子进程写数据给管道2
14 int wfd=-1;
15 if((wfd=open("./myfifo2",O_WRONLY))==-1)
16 {
17 perror("open myfifo2 error");
18 return -1;
19 }
20 char buf[128]="";
21 while(1)
22 {
23 bzero(buf,sizeof(buf));//清空数组
24 fgets(buf,sizeof(buf),stdin);
25 buf[strlen(buf)-1]=0;
26 //写入数据
27 write(wfd,buf,strlen(buf));
28 if(strcmp(buf,"quit")==0)
29 break;
30 }
31 //关闭文件
32 close(wfd);
33 //退出进程
34 exit(EXIT_SUCCESS);
35 }else
36 {
37 //父进程读取管道1
38 int rfd=-1;
39 if((rfd=open("./myfifo1",O_RDONLY))==-1)
40 {
41 perror("open myfifo1 error");
42 return -1;
43 }
44 char buf[128]="";
45 while(1)
46 {
47 bzero(buf,sizeof(buf));
48 //读取数据
49 read(rfd,buf,sizeof(buf));
50 printf("读取数据:%s\n",buf);
51 if(strcmp(buf,"quit")==0)
52 break;
53 }
54 //关闭文件
55 close(rfd);
56 wait(NULL);//回收子进程资源
57 }
58 return 0;
59 }
运行结果:
流程图: