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