为什么copyfilepass
返回指向callcopypass
可以将此值作为args[2]
访问时复制的字节数的指针?
#include <unistd.h>
#include "restart.h"
void *copyfilepass(void *arg) {
int *argint;
argint = (int *)arg;
/* copyfile copies from a descriptor to another */
argint[2] = copyfile(argint[0], argint[1]);
close(argint[0]);
close(argint[1]);
return argint + 2;
}
callcopypass.c
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#define PERMS (S_IRUSR | S_IWUSR)
#define READ_FLAGS O_RDONLY
#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
void *copyfilepass(void *arg);
int main (int argc, char *argv[]) {
int *bytesptr;
int error;
int targs[3];
pthread_t tid;
if (argc != 3) {
fprintf(stderr, "Usage: %s fromfile tofile\n", argv[0]);
return 1;
}
if (((targs[0] = open(argv[1], READ_FLAGS)) == -1) ||
((targs[1] = open(argv[2], WRITE_FLAGS, PERMS)) == -1)) {
perror("Failed to open the files");
return 1;
}
if (error = pthread_create(&tid, NULL, copyfilepass, targs)) {
fprintf(stderr, "Failed to create thread: %s\n", strerror(error));
return 1;
}
if (error = pthread_join(tid, (void **)&bytesptr)) {
fprintf(stderr, "Failed to join thread: %s\n", strerror(error));
return 1;
}
printf("Number of bytes copied: %d\n", *bytesptr);
return 0;
}
作者回答说
如果创建线程以外的线程与
copyfilepass
连接,则为 可以访问通过参数复制的字节数pthread_join
。
我甚至不理解答案。另一个线程如何访问返回值(即更改值?)而不是创建一个?如果可能的话,你能解释一下吗?
答案 0 :(得分:2)
答案的关键是你可以预见到要从创建它的线程以外的线程读取copyfilepass
线程的结果(在这种情况下是复制的字节数)。假设,为了示例,我们有第三个线程monitorcopy
,而tid
是全局而不是局部变量。 monitorcopy
在主方法copyfilepass
之后生成。
void* monitorcopy(void* params) {
void *result
pthread_join(tid, &result);
/* Point A: Attempt to read result */
}
假设copyfilepass
返回NULL
或无意义的值。在A点,result
是NULL
,我们无法检索复制的字节数,因为它存储在main方法的targs[2]
中,超出了范围。< / p>
假设copyfilepass
返回argint + 2
。 result
现在是指向复制的字节数的指针,即使我们与targs
的范围不同。因此,在没有任何内存生存期问题的情况下,我们可以按如下方式访问复制的字节数:
void* monitorcopy(void* params) {
void *result
pthread_join(tid, &result);
int bytesCopied = *((int*) result);
}
答案 1 :(得分:2)
问题不在于另一个线程想要&#34;更改返回值&#34;,它是否有不同的线程可以访问输入参数(targs
)。通常,pthread_join
允许您从程序中的任何位置获取某个线程的结果值,只要您拥有线程ID即可。因此,使用此值返回异步操作的结果是不明智的?
然而,这个例子写得很差(作为良好的多线程实践的一个例子),原因有很多:
只有一个函数,所有变量的范围都延伸到main
。这样写,无论如何每个人都可以访问输入参数。当你说在这种情况下通过pthread_join
阅读结果时,你是对的。
将堆栈变量(targs
)传递给线程是一个坏主意。当函数结束时,变量将超出范围,因此程序不会崩溃的唯一安全方法是立即加入线程,防止targs
超出范围。这意味着你不会从多线程中获得任何好处(除非main
在加入之前做了一些额外的工作)。它们应该是全局的,或者在堆上分配(malloc
/ free
对)。
文件在main
内打开,但在copyfilepass
内关闭。这种责任转移是不必要的,尽管并不罕见。我会将文件名传递给函数并处理那里的开头,或者在复制文件后关闭线程外的句柄。
无论如何,代码作者的观点是,您不需要在您加入主题的地方访问输入参数:
// removed all error checks for simplicity
int main (int argc, char *argv[]) {
pthread_t tid;
// removed all error checks for simplicity
pthread_create(&tid, NULL, copy_file, argv);
// note that this function only accepts the thread id
wait_until_copied(tid);
return 0;
}
void wait_until_copied(pthread_t tid)
{
int *bytesptr;
// no way to access input args here
pthread_join(tid, (void **)&bytesptr);
printf("Number of bytes copied: %d\n", *bytesptr);
}