簡體   English   中英

除了創建一個線程以外,另一個訪問線程的返回值

[英]Accessing to return value of a thread by another one other than creating one

callcopypass可以以args[2]訪問此值時,為什么copyfilepass返回一個指向復制的字節數的指針?

#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的字節數。

我什至不理解答案。 除了創建一個線程外,另一個線程如何訪問返回值(即更改值?)? 您能否舉例說明一下?

答案的症結在於,可以預見的是,您可能希望從創建它的線程之外的其他線程讀取copyfilepass線程的結果(在這種情況下為復制的字節數)。 舉例來說,假設我們有第三個線程monitorcopy ,並且tid是全局變量而不是局部變量。 從main方法的copyfilepass之后生成monitorcopy

void* monitorcopy(void* params) {
  void *result
  pthread_join(tid, &result);
  /* Point A: Attempt to read result */
}

假設copyfilepass返回NULL或無意義的值。 在點A, resultNULL ,我們無法檢索復制的字節數,因為它存儲在main方法的targs[2]中,這超出了范圍。

假設copyfilepass返回argint + 2 result現在是指向復制的字節數的指針,即使我們與targs不在同一范圍內。 因此,在沒有任何內存生存期問題的情況下,我們可以按以下方式訪問復制的字節數:

void* monitorcopy(void* params) {
  void *result
  pthread_join(tid, &result);
  int bytesCopied = *((int*) result);
}

問題不在於另一個線程想要“更改返回值”,而是另一個線程是否可以訪問輸入參數( targs )。 通常, pthread_join允許您從某個線程,程序中的任何位置獲取結果值,只要您具有線程ID即可。 那么使用此值返回異步操作的結果是否明智?

但是,由於許多原因,此示例的編寫不佳(作為良好的多線程實踐的示例):

  1. 只有一個函數,所有變量的范圍都通過main擴展。 這樣寫, 每個人無論如何都可以訪問輸入參數 您說對了,在這種情況下不需要通過pthread_join讀取結果是正確的。

  2. 將堆棧變量( targs )傳遞給線程是一個壞主意 當函數結束時,變量將超出范圍,因此,不使程序崩潰的唯一安全方法是立即加入線程,以防止targs超出范圍。 這意味着您沒有多線程的任何好處(除非main在加入之前做了一些額外的工作)。 它們應該是全局的,也應該在堆上分配(一個malloc / free對)。

  3. 文件在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);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM