Linux--多线程拷贝文件案例及其传参说明

本文介绍了一个使用多线程进行文件拷贝的C程序案例,并探讨了在多线程环境中如何正确地传递参数给线程函数,避免因堆栈解旋导致的数据问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面的简单案例模拟了多线程拷贝一个文件

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>

#define MAX_PATH 255
#define BLOCK_SIZE 4096

typedef struct 
{
	int srcFd;
	int dstFd;
	int start;
	int end;
}thread_info;

int copy(const char *src, const char *dst, int threads);
void *run(void *arg);

pthread_t *tid = NULL;
thread_info *tinfo = NULL;

int main(int argc, char *argv[])
{
	if (argc != 4)
	{
		printf("usage: %s src dst sum_of_thread\n", argv[0]);
		return -1;
	}
	
	char src[MAX_PATH] = {0};
	char dst[MAX_PATH] = {0};
	int threads;
	
	memcpy(src, argv[1], strlen(argv[1]));
	memcpy(dst, argv[2], strlen(argv[1]));
	threads = atoi(argv[3]);
	
	if (threads <= 0)
	{
		threads = 1;
	}
	
	struct stat srcInfo;
	struct stat dstInfo;
	
	if (stat(src, &srcInfo) < 0)
	{
		perror("main: stat src");
		return -1;
	}
	
	if (srcInfo.st_mode & S_IFDIR)
	{
		printf("the src must be file\n");
		return -1;
	}
	
	if (access(dst, F_OK) == 0)
	{
		if (stat(dst, &dstInfo) < 0)
		{
			perror("main: stat dst");
			return -1;
		}
		
		if (!(dstInfo.st_mode & S_IFDIR))
		{
			unlink(dst);
		}
	}
	
	int fd = open(dst, O_CREAT | O_EXCL, 0644);
	if (fd < 0)
	{
		perror("main: open dst");
		return -1;
	}
	
	tid = (pthread_t *)malloc(threads * sizeof(pthread_t));
	if (tid == NULL)
	{
		printf("main: malloc pthread");
		return -1;
	}
	
	tinfo = (thread_info *)malloc(threads * sizeof(thread_info));
	if (tinfo == NULL)
	{
		printf("main: malloc thread_info");
		return -1;
	}
	
	copy(src, dst, threads);
	
	int i = 0;
	for (; i < threads; ++i)
	{
		pthread_join(tid[i], NULL);
	} 
	
	free(tid);
	free(tinfo);
	return 0;
}

int copy(const char *src, const char *dst, int threads)
{
	assert(src != NULL);
	assert(dst != NULL);
	
	int srcFd = open(src, O_RDWR);
	if (srcFd < 0)
	{
		perror("copy: open src");
		return -1;
	}
	
	int dstFd = open(dst, O_RDWR);
	if (dstFd < 0)
	{
		perror("copy: open dst");
		return -1;
	}
	
	struct stat srcInfo;
	if (stat(src, &srcInfo) < 0)
	{
		perror("copy: stat src");
		return -1;
	}
	
	off_t size = srcInfo.st_size;
	lseek(dstFd, size, SEEK_SET);
	write(dstFd, '\0', 1);
	
	int i = 0;
	for(; i < threads; ++i)
	{
		//printf("i=%d\n", i);
		int start = i * (size/threads);
		int end = 0;
		
		if (i == threads - 1)
		{
			end = size;
		}
		else
		{
			end = (i+1) * (size/threads);
		}
		
		tinfo[i].srcFd = srcFd;
		tinfo[i].dstFd = dstFd;
		tinfo[i].start = start;
		tinfo[i].end = end;
		
		//printf("begin-info: src_fd(%d), dst_fd(%d), start(%d), end(%d)\n", tinfo[i].srcFd, tinfo[i].dstFd, tinfo[i].start, tinfo[i].end);
		pthread_create(&tid[i], NULL, run, (void *)&tinfo[i]);	
	}
}

void *run(void *arg)
{
	thread_info tinfo = *(thread_info *)arg;
	
	//printf("info: src_fd(%d), dst_fd(%d), start(%d), end(%d)\n", tinfo.srcFd, tinfo.dstFd, tinfo.start, tinfo.end);
	if (lseek(tinfo.srcFd, tinfo.start, SEEK_SET) < 0)
	{
		perror("run: lseek src");
		pthread_exit((void *)-1);
	}
	
	if (lseek(tinfo.dstFd, tinfo.start, SEEK_SET) < 0)
	{
		perror("run: lseek dst");
		pthread_exit((void *)-1);
	}
	
	int length = tinfo.end - tinfo.start;
	int size = 0;
	char line[BLOCK_SIZE] = {0};
	int readSize = 0;
	
	do
	{
		if (length > 0 && length <= BLOCK_SIZE)
		{
			readSize = length;
		}
		else if (length > 0 && length > BLOCK_SIZE)
		{
			readSize = BLOCK_SIZE;
		}
		else
		{
			break;
		}
		size = read(tinfo.srcFd, line, readSize);
	
		write(tinfo.dstFd, line, size);
		
		length -= size;
		
		memset(line, 0x0, sizeof(line));
		
	}while(1);
	
	return (void *)0;
}




*其中需要注意的是,对于多线程的传参问题。之前很多案例上都是在main函数中调用pthread_create,然后传递一个参数给线程主函数。这样几乎不会出现问题,能够出现问题的情况是,对于以下案例,将pthread_create在另一个函数中调用,传递参数的问题

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

int start = 1000;
void *run(void *arg)
{
	int start = *(int *)arg;
	printf("start = %d\n", start);
}

void startThread(pthread_t *tid)
{
	int state = 200;
	//pthread_create(tid, NULL, run, (void *)&start);
	pthread_create(tid, NULL, run, (void *)&state);
}

int main()
{
	pthread_t tid;
	
	startThread(&tid);
	
	//pthread_join(tid, NULL);
	sleep(3);
	
	return 0;
}

在run中打印start得到的是一个0值。在前后打印出地址,发现地址没有改变,值却变了。经过摸索,得到的结论是,在startThread函数中,当调用pthread_create之后整个函数返回,相当于函数的堆栈解旋了。那时候的局部变量state被覆盖,显而易见地址是不变的。当调用run函数时候,run函数的堆栈段是一个新的地址空间,或许就是覆盖了startThread函数的。

那么,如果我想在线程函数中传递参数,可以使用以下三类:

1. 全局变量,静态变量

2. 简单的传值(这里的传值指在run函数中能够不需要间接引用就能获取的)

3. 堆数据(malloc,new)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值