【问题标题】:main doesn't continue after call pthread_join function调用 pthread_join 函数后 main 不继续
【发布时间】:2017-06-21 04:08:57
【问题描述】:

我是 pthread 和多线程的新手,我写过这样的代码。

#include <pthread.h>
#include <unistd.h>


void *nfc_read(void *arg)
{
    int fd = -1;   
    int ret;
    uint8_t read_data[24];

    while(1){
        ret = read_block(fd, 8, read_data);
        if(!ret){
            return (void)read_data;
        }
    }
}

int main(int argc, char *argv[])
{
    pthread_t my_thread;
    void  *returnValue;

    pthread_create(&my_thread, NULL, nfc_read, NULL);
    pthread_join(my_thread, &returnValue);

    printf("NFC card value is : %s \n", (char)returnValue);

    printf("other process");

  return 0;
}

直到 nfc_read 函数的返回值,因为我将有其他代码需要运行并且我不想阻塞在 main 中。我该怎么做?

【问题讨论】:

  • 您将pthread_join 放在您确实需要完成该功能的位置。
  • 如果您不想阻止,请不要致电pthread_join。如果您需要线程的结果,那么您将需要在某个时候阻塞或轮询。目前还不清楚你想要什么行为。
  • 另请注意,您返回的本地数组在函数完成后无法使用
  • @Scheff 即使对于像这样的“简单”事情,volatile 也是不够的:线程可能在不同的 CPU 上运行,因此需要内存屏障。最简单的使用方法可能是 pthread 互斥锁和条件变量。
  • 调用pthread_create 紧跟pthread_join 只是调用函数的一种非常低效的方式。

标签: c multithreading pthreads


【解决方案1】:

这是一个示例,其中读取线程与正在执行其他工作(在本例中为打印点和休眠)的“主”线程同时运行。

为了简单起见,我们通过逐个字符复制常量字符串来模拟输入设备的读取。我想,这是合理的,因为关注线程的同步。

对于线程的同步,我使用了atomic_boolatomic_store()atomic_load(),它们由Atomic Library 提供(C11 起)。

我的示例应用程序test-concurrent-read.c

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

/* sampe input */
const char sampleInput[]
  = "This is sample input which is consumed as if it was read from"
    " a (very slow) external device.";

atomic_bool readDone = ATOMIC_VAR_INIT(0);

void* threadRead(void *pArg)
{
  char **pPBuffer = (char**)pArg;
  size_t len = 0, size = 0;
  int c; const char *pRead;
  for (pRead = sampleInput; (c = *pRead++) > 0; sleep(1)) {
    if (len + 1 >= size) {
      if (!(*pPBuffer = realloc(*pPBuffer, (size + 64) * sizeof(char)))) {
        fprintf(stderr, "ERROR! Allocation failed!\n");
        break;
      }
      size += 64;
    }
    (*pPBuffer)[len++] = c; (*pPBuffer)[len] = '\0';
  }
  atomic_store(&readDone, 1);
  return NULL;
}

int main()
{
  /* start thread to read concurrently */
  printf("Starting thread...\n");
  pthread_t idThreadRead; /* thread ID for read thread */
  char *pBuffer = NULL; /* pointer to return buffer from thread */
  if (pthread_create(&idThreadRead, NULL, &threadRead, &pBuffer)) {
    fprintf(stderr, "ERROR: Failed to start read thread!\n");
    return -1;
  }
  /* start main loop */
  printf("Starting main loop...\n");
  do {
    putchar('.'); fflush(stdout);
    sleep(1);
  } while (!atomic_load(&readDone));
  putchar('\n');
  void *ret;
  pthread_join(idThreadRead, &ret);
  /* after sync */
  printf("\nReceived: '%s'\n", pBuffer ? pBuffer : "<NULL>");
  free(pBuffer);
  /* done */
  return 0;
}

在 Windows 10(64 位)的 cygwin 中使用 gcc 编译和测试:

$ gcc -std=c11 -pthread -o test-concurrent-read test-concurrent-read.c

$ ./test-concurrent-read
Starting thread...
Starting main loop...
.............................................................................................

Received: 'This is sample input which is consumed as if it was read from a (very slow) external device.'

$ 

我想,值得一提的是为什么在main()threadRead() 中使用的pBuffer 没有互斥保护。

  1. pBuffermain() 中初始化之前 pthread_create() 被调用。

  2. thread_read() 运行时,pBuffer 被它独占使用(通过它在pPBuffer 中传递的地址)。

  3. 再次在main() 中访问,但不是在此之前pthread_join() 表示threadRead() 已结束。

我试图通过谷歌找到一个参考来确认这个过程是明确和合理的。我能找到的最好的是SO: pthread_create(3) and memory synchronization guarantee in SMP architectures,它引用了The Open Group Base Specifications Issue 7 - 4.12 Memory Synchronization

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    相关资源
    最近更新 更多