2023/3/3日作业

文章展示了三个多线程编程的例子,分别用条件变量实现文件内容的读取和打印,以及线程间特定顺序的打印。第一个例子中,A线程读取文件,B线程打印,通过条件变量和互斥锁保证同步。第二个例子使用两个条件变量控制ABC三个线程按序打印。第三个例子利用信号量实现数据的交换与打印,达到倒置和显示的交替效果。
摘要由CSDN通过智能技术生成

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:作业$ 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

malingshu404

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值