线程基础与信号量 2024.8.27

作业一:创建3个线程,一个子线程拷贝文件的前一半,一个子线程拷贝后一半文件,主线程回收子线程资源。

知识点:线程相较于进程,能够很方便的共享数据,因为多个线程对于全局变量修改读取同一个地址。

因为线程的执行由cpu决定,并发时具有不可预测的特点,因此需要特别注意多个线程访问同一个地址的或者输出的顺序问题,一般采用以下方法对地址进行保护。

  • 进程互斥锁:适合在多线程间保护共享资源,防止竞争条件。
  • 无名信号量:适合在生产者-消费者模型中控制线程对资源的并发访问。
  • 条件变量:适合用于实现线程的同步,等待特定的条件完成。
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#define BUF_SIZE 1000

typedef struct{
	FILE *source_file;
	FILE *dest_file;
	long file_start;
	long file_end;
}ThreadData;

void *copy_half(void *arg){
    //获取创建线程传递的参数
	ThreadData *data=(ThreadData*)arg;

    //将文件指针设置到开始位置
	fseek(data->source_file,data->file_start,SEEK_SET);

	fseek(data->dest_file,data->file_start,SEEK_SET);
    //每次读取,写值和剩余值

	size_t f_read,f_write,remaining=data->file_end-data->file_start;
    //缓冲区	
    char buf[BUF_SIZE];

	while(1){
		f_read=remaining>BUF_SIZE?BUF_SIZE:remaining;
		f_write=fread(buf,1,f_read,data->source_file);

		//如果读取值为0退出,注意不可以用剩余值<=0,因为可能因为读取值为0,剩余值-=写入值不<=0
        if(f_write<=0)break;

		f_write=fwrite(buf,1,f_write,data->dest_file);
		remaining-=f_write;
	}
	return NULL;
}

int main(int argc, const char *argv[])
{
    //打开文件
	FILE *src=fopen("1.txt","rb");
    FILE *src2=fopen("1.txt","rb");
	FILE *des=fopen("2.txt","wb");

	if(!src|!des){
		printf("文件打开失败");
		return -1;
	}

    //设置指针到文件末尾计算文件大小,和文件一半。
	fseek(src,0,SEEK_END);

	long file_size=ftell(src);
	long half_size=file_size/2;

    //赋值参数
	ThreadData data1={src,des,0,half_size};
	ThreadData data2={src2,des,half_size,file_size};

	pthread_t thread1,thread2;//一般这些_t都是type的意思统一用于跨平台。

    //创建线程,参数一为储存线程Id,2为线程属性结构体,填写NULL为默认。3.要执行的函数。4.参数
	pthread_create(&thread1,NULL,copy_half,&data1);
	pthread_create(&thread2,NULL,copy_half,&data2);

	//等待回收线程,参数1为要回收的线程Id,2为储存的线程结束返回值
	pthread_join(thread1,NULL);
	pthread_join(thread2,NULL);

    //关闭打开的文件。
	fclose(src);
    fclose(src2);
	fclose(des);

	return 0;
}

作业二:使用无名信号量实现循环输出春、夏、秋、冬。

sem_init通知操作系统创建初始化信号量,这个信号量会在内部维护一个计数器和阻塞队列。在通过sem_post和sem_wait来修改信号量,进而实现间接控制阻塞队列,实现线程的执行与阻塞。
 

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

//定义sem变量
sem_t sem_spring,sem_summer,sem_autumn,sem_winter;

void *print_spring(void *args){
	while(1){
        //减信号量
		sem_wait(&sem_spring);
		printf("春\n");
        //加信号量
		sem_post(&sem_summer);
	}
}
void *print_summer(void *args){
	while(1){
		sem_wait(&sem_summer);
		printf("夏\n");
		sem_post(&sem_autumn);
	}
}
void *print_autumn(void *args){
	while(1){
		sem_wait(&sem_autumn);
		printf("秋\n");
		sem_post(&sem_winter);
	}
}
void *print_winter(void *args){
	while(1){
		sem_wait(&sem_winter);
		printf("冬\n");
		sem_post(&sem_spring);
	}
}

int main(int argc, const char *argv[])
{
    //初始化信号量,参数为信号量地址,是否进程间通信,初始值。
	sem_init(&sem_spring,0,1);
	sem_init(&sem_summer,0,0);
	sem_init(&sem_autumn,0,0);
	sem_init(&sem_winter,0,0);

	pthread_t p1,p2,p3,p4;
	pthread_create(&p1,NULL,print_spring,NULL);
	pthread_create(&p2,NULL,print_summer,NULL);
	pthread_create(&p3,NULL,print_autumn,NULL);
	pthread_create(&p4,NULL,print_winter,NULL);
	
	pthread_join(p1,NULL);
	pthread_join(p2,NULL);
	pthread_join(p3,NULL);
	pthread_join(p4,NULL);

    //销毁信号量
	sem_destroy(&sem_spring);
	sem_destroy(&sem_summer);
	sem_destroy(&sem_autumn);
	sem_destroy(&sem_winter);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值