下面的简单案例模拟了多线程拷贝一个文件
#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)