1、将一个文件中的数据打印到终端上,类似cat一个文件。要求如下
a.A线程读取文件中的数据
b.B线程将A线程读取到的数据打印到终端上
c.文件打印完毕后,结束进程.
程序代码
1 #include<stdio.h>
2 #include<pthread.h>
3 #include<semaphore.h>
4 #include<string.h>
5 //定义一个全局流指针(也可以在主函数定义,通过传参传入到子线程)
6 FILE *fp=NULL;
7 //创建并初始化一个条件变量
8 pthread_cond_t cond1=PTHREAD_COND_INITIALIZER;
9 //创建并初始化一把互斥锁
10 pthread_mutex_t fastmute=PTHREAD_MUTEX_INITIALIZER;
11 //定义一个变量,通过该变量判断是否执行程序
12 int a=1;
13 char arr[30]="";
14 //读函数
15 void *callBackRead(void *arg)
16 {
17 while(1)
18 {
19 /********循环体*******/
20 //进入循环体,上p锁
21 pthread_mutex_lock(&fastmute);
22 if(a==2)
23 pthread_cond_wait(&cond1,&fastmute);//当前线程休眠,设置一个唤醒条件,等待被唤醒(需要互斥锁的配合)
24 if(1==a)
25 {
26 bzero(arr,sizeof(arr));
27 if(NULL==fgets(arr,sizeof(arr)-1,fp))
28 {
29 a=3;
30 }
31 else
32 {
33 a=2;
34 }
35 }
36 pthread_cond_signal(&cond1);//唤醒在条件变量上的线程
37 //解锁
38 pthread_mutex_unlock(&fastmute);
39 if(3==a)
40 break;
41 /********循环体********/
42 }
43 pthread_exit(NULL);
44 }
45 void *callBackWrite(void *arg)
46 {
47 while(1)
48 {
49 /********循环体*******/
50 //进入循环体,上锁
51 pthread_mutex_lock(&fastmute);
52 if(a==1)
53 pthread_cond_wait(&cond1,&fastmute);//当前线程休眠,设置一个唤醒条件,等待被唤醒(需要互斥锁的配合
54 if(3==a)
55 {
56 break;
57 }
58
59 if(2==a)
60 {
61
62 fprintf(stdout,"%s",arr);
63 a=1;
64 pthread_cond_signal(&cond1);//唤醒睡在条件变量上的线程
65 }
66 //解锁
67 pthread_mutex_unlock(&fastmute);
68 /********循环体********/
69 }
70 pthread_exit(NULL);
71 }
72
73 int main(int argc, const char *argv[])
74 {
75 //pthread_mutex_init(fastmute,NULL) 创建互斥锁的另外一种方式
76 //用只读的方式打开一个文件
77 fp=fopen("./copy_pic_doubleline.c","r");
78 if(fp==NULL)
79 {
80 perror("fopen");
81 return -1;
82 }
83 printf("******");
84 #if 1
85 //创建两个子线程,
86 pthread_t ppid1,ppid2;
87 pthread_create(&ppid1,NULL,callBackRead,NULL);
88 pthread_create(&ppid2,NULL,callBackWrite,NULL);
89
90
91 //接受子线程返回值
92 pthread_join(ppid1,NULL);
93 pthread_join(ppid2,NULL);
94 //销毁互斥锁
95 pthread_mutex_destroy(&fastmute);
96 //销毁条件变量
97 pthread_cond_destroy(&cond1);
98 //关闭流指针
99 fclose(fp);
100 #endif
101 return 0;
102 }
~
运行结果(代码段即为复制到终端的结果)
ubuntu@ubuntu:作业$ gcc cat_wenjain.c -pthread
ubuntu@ubuntu:作业$ ./a.out
******#include<stdio.h>
#include<time.h>
#include<pthread.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
void *callBack(void *arg)
{
FILE *fp1=fopen("./2023-02-14 10-49-42 的屏幕截图.png","r");
if(NULL==fp1)
{
perror("open");
}
FILE *fp2=fopen("./copy_pic.png","w");
if(NULL==fp2)
{
perror("open");
}
struct stat pp;
if(stat("./2023-02-14 10-49-42 的屏幕截图.png",&pp))
{
perror("stat");
}
//使用getc时,目标文件可能会有字符'EOF',影响对getc的判断
//故不推荐使用getc函数实现打印
int size=pp.st_size;
int flag=size%2;
char a;
int i;
for(i=0;i<size/2;i++)
{
a=fgetc(fp1);
fputc(a,fp2);
}
char arr[32]="";
fclose(fp1);
fclose(fp2);
printf("子线程前半部分打印完成\n");
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
//创建子线程
//子线程拷贝前半部分,拷贝完成后返回给主线程
pthread_t ttid;//保存子线程的tid号
if(pthread_create(&ttid,NULL,callBack,NULL)!=0)
{
fprintf(stderr,"pthread_creat failed __%d__",__LINE__);
return -1;
}
//主线程,阻塞等待子线程拷贝完成后拷贝后半部分
pthread_join(ttid,NULL);
FILE *fp1=fopen("./2023-02-14 10-49-42 的屏幕截图.png","r");
if(NULL==fp1)
{
perror("open");
return -1;
}
FILE *fp2=fopen("./copy_pic.png","a+");
if(NULL==fp2)
{
perror("open");
return -1;
}
struct stat pp;
if(stat("./2023-02-14 10-49-42 的屏幕截图.png",&pp))
{
perror("stat");
return -1;
}
int size=pp.st_size;
int flag=size%2;
fseek(fp1,size/2,SEEK_SET);
fseek(fp2,size/2,SEEK_SET);
char b;
int i;
for(i=size/2+flag;i<=size;i++)
{
b=fgetc(fp1);
fputc(b,fp2);
}
printf("主线程后半部分打印完成\n");
fclose(fp1);
fclose(fp2);
return 0;
}
2、用条件变量实现,有编号为ABC的三个线程,线程内分别打印自己的线程编号,要求打印的顺序为ABC
提示:多个条件变量
程序代码:
1 #include<stdio.h>
2 #include<pthread.h>
3 #include<semaphore.h>
4 #include<string.h>
5 //创建并初始化两个条件变量
6 pthread_cond_t cond1=PTHREAD_COND_INITIALIZER;
7 pthread_cond_t cond2=PTHREAD_COND_INITIALIZER;
8 pthread_cond_t cond3=PTHREAD_COND_INITIALIZER;
9 //创建并初始化一把互斥锁
10 pthread_mutex_t fastmute=PTHREAD_MUTEX_INITIALIZER;
11 int a=1;
12 //定义一个变量,通过该变量判断是否执行程序
13 void *callBackppid1(void *arg)
14 {
15 while(1)
16 {
17 /********循环体*******/
18 //进入循环体,上p锁
19 pthread_mutex_lock(&fastmute);
20 if(a!=1)
21 pthread_cond_wait(&cond1,&fastmute);//当前线程休眠,设置一个唤醒条件,等待被唤醒(需要互斥锁的配合)
22 if(1==a)
23 {
24 printf("ppid1=%d\n",*(int *)arg);
25 a=2;
26 }
27 pthread_cond_signal(&cond2);//唤醒在条件变量上的线程
28 pthread_cond_signal(&cond3);//唤醒在条件变量上的线程
29 //解锁
30 pthread_mutex_unlock(&fastmute);
31 if(4==a)
32 break;
33 /********循环体********/
34 }
35 pthread_exit(NULL);
36 }
37 void *callBackppid2(void *arg)
38 {
39 while(1)
40 {
41 /********循环体*******/
42 //进入循环体,上锁
43 pthread_mutex_lock(&fastmute);
44 if(a!=2)
45 pthread_cond_wait(&cond2,&fastmute);//当前线程休眠,设置一个唤醒条件,等待被唤醒(需要互斥锁的配合
46 if(2==a)
47 {
48 a=3;
49 printf("ppid2=%d\n",*(int *)arg);
50 }
51 pthread_cond_signal(&cond1);//唤醒睡在条件变量上的线程
52 pthread_cond_signal(&cond3);//唤醒睡在条件变量上的线程
53
54 //解锁
55 pthread_mutex_unlock(&fastmute);
56 if(a==4)
57 break;
58 /********循环体********/
59 }
60 pthread_exit(NULL);
61 }
62 void *callBackppid3(void *arg)
63 {
64 while(1)
65 {
66 /********循环体*******/
67 //进入循环体,上锁
68 pthread_mutex_lock(&fastmute);
69 if(a!=3)
70 pthread_cond_wait(&cond3,&fastmute);//当前线程休眠,设置一个唤醒条件,等待被唤醒(需要互斥锁的配合
71 if(3==a)
72 {
73 a=4;
74 printf("ppid3=%d\n",*(int *)arg);
75 }
76 pthread_cond_signal(&cond1);//唤醒睡在条件变量上的线程
77 pthread_cond_signal(&cond2);//唤醒睡在条件变量上的线程
78 //解锁
79 pthread_mutex_unlock(&fastmute);
80 if(a==4)
81 break;
82 /********循环体********/
83 }
84 pthread_exit(NULL);
85 }
86
87
88 int main(int argc, const char *argv[])
89 {
90 //pthread_mutex_init(fastmute,NULL) 创建互斥锁的另外一种方式
91 //用只读的方式打开一个文件
92 #if 1
93 //创建三个子线程,
94 pthread_t ppid1,ppid2,ppid3;
95 pthread_create(&ppid1,NULL,callBackppid1,&ppid1);
96 pthread_create(&ppid2,NULL,callBackppid2,&ppid2);
97 pthread_create(&ppid3,NULL,callBackppid3,&ppid3);
98
99
100 //接受子线程返回值
101 pthread_join(ppid1,NULL);
102 pthread_join(ppid2,NULL);
103 pthread_join(ppid3,NULL);
104 //销毁互斥锁
105 pthread_mutex_destroy(&fastmute);
106 //销毁条件变量
107 pthread_cond_destroy(&cond1);
108 #endif
109 return 0;
110 }
运行结果:
ubuntu@ubuntu:作业$ gcc name_pthread.c -pthread
ubuntu@ubuntu:作业$ ./a.out
ppid1=-2013878528
ppid2=-2022271232
ppid3=-2030663936
3、要求用信号量的方式实现,打印一次倒置一次。不允许使用flag
程序代码:
1 #include<stdio.h>
2 #include<time.h>
3 #include<pthread.h>
4 #include<string.h>
5 #include<unistd.h>
6 #include<semaphore.h>
7 //临界资源
8 char buf[]="1234567";
9 //创建信号量
10 sem_t sem;
11 int a=0;
12 void *callBack_swap(void *arg)
13 {
14
15 while(1)
16 {
17 /**********临界区**********/
18 if(0==a)
19 {
20 //P操作
21 sem_wait(&sem);
22 for(int i=0,j=strlen(buf)-1;i<j;i++,j--)
23 {
24 buf[i]=buf[i]+buf[j];
25 buf[j]=buf[i]-buf[j];
26 buf[i]=buf[i]-buf[j];
27 }
28 //V操作
29 a=1;
30 sem_post(&sem);
31 /**********临界区**********/
32 }
33 }
34 pthread_exit(NULL);
35 }
36 void *callBack_print(void *arg)
37 {
38 while(1)
39 {
40 if(1==a)
41 {
42 /**********临界区**********/
43 sem_wait(&sem);
44 printf("%s\n",buf);
45 a=0;
46 sem_post(&sem);
47 /**********临界区**********/
48 }
49 }
50 }
51
52 int main(int argc, const char *argv[])
53 {
54 pthread_t ttid1,ttid2;
55 if(pthread_create(&ttid1,NULL,callBack_swap,NULL)!=0)
56 {
57 fprintf(stderr,"pthread_creat failed __%d__",__LINE__);
58 return -1;
59 }
60 if(pthread_create(&ttid2,NULL,callBack_print,NULL)!=0)
61 {
62 fprintf(stderr,"pthread_creat failed __%d__",__LINE__);
63 return -1;
64 }
65 //创建信号量,由于同时只允许一个线程运行,故初始值为1
66 if(0>sem_init(&sem,0,1))
67 {
68 perror("sem_init");
69 return -1;
70 }
71
72 //阻塞等待子线程返回
73 pthread_join(ttid1,NULL);
74 pthread_join(ttid2,NULL);
75 //销毁信号量
76 sem_destroy(&sem);
77 return 0;
78 }
运行结果:
7654321
1234567
7654321
1234567
7654321
1234567
7654321
^Z
[5]+ 已停止 ./a.out
ubuntu@ubuntu:作业$