【问题标题】:Problem with Boehm gc and mutli-thread programBoehm gc 和多线程程序的问题
【发布时间】:2020-03-03 12:38:53
【问题描述】:

在多线程程序中使用Boehmgarbage 收集器时遇到问题。
我的主函数休眠,而线程正在使用垃圾收集器执行一些分配和释放。

当垃圾收集器调用collect()时,主线程的睡眠被中断,程序继续进行,就像什么都没发生一样。

以下源代码在 1 秒后终止,而它必须至少休眠 100 秒:

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

#define GC_THREADS
#include <gc/gc.h>

void foo () {
    sleep (1);
    GC_gcollect (); // or multiple allocation, that will trigger a collect at some point
}

void * thread_func (void* data) {
    foo ();
}

int main () {
    // GC_init (); ordinarily useless, and does not change anything 
    pthread_t id;
    GC_pthread_create (&id, NULL, &thread_func, NULL);
    sleep (100);
    printf ("End \n");
}

同样的问题发生在线程处于休眠状态和执行分配的主函数时。 我在ubuntu-18.04 上使用bohem gc 的最后一个稳定版本(即8.0.4)。

有人知道发生了什么吗?

【问题讨论】:

  • 我打赌 sleep 返回错误代码 EINTR。
  • @Emile Cadorel - 你的意思是“Boehm GC”吗?
  • 如果您使用 C 编译器而不是 C++ 编译器进行编译,我认为您实际上应该调用 GC_init()。但我不明白为什么 sleep() 不起作用。 sleep() 返回什么?
  • 是的,对不起 Boehm GC。该函数返回值98,所以不是EINTR,它等于498 是 errno.h 中 EADDRINUSE 的值
  • sleep() 返回98,errno 设置为4

标签: c multithreading garbage-collection


【解决方案1】:

垃圾收集器在内部使用许多信号(根据 debugging documentationSIGSEGVSIGBUS 以及 SIGPWRSIGXCPU 在您使用的多线程 linux 设置上),并设置它们的信号处理函数。

sleep() 将在调用信号处理程序时被中断,并返回如果未中断则超时之前剩余的秒数。如果在睡眠中触发集合,就会发生这种情况。

因此,如果您想将 sleep() 与垃圾收集器混合使用,则必须使用如下循环:

int timeout = 100;
int time_remaining;
while ((time_remaining = sleep(timeout)) > 0) {
  timeout = time_remaining;
}

更健壮的实现直接使用nanosleep()(这就是sleep() 在Linux+Glibc 上的实现方式)以更好地处理错误:

struct timespec req = { .tv_sec = 100, .tv_nsec = 0 };
struct timespec rem;
while (nanosleep(&req, &rem) < 0) {
  if (errno == EINTR) {
    // Interrupted by a signal handler
    req = rem;
  } else {
    // Some other error happened; handle appropriately for your application
    perror("nanosleep");
    exit(EXIT_FAILURE);
  }
}

一个更加健壮的版本,由于垃圾收集器使用的时间,它不会休眠超过 100 秒(除非到目前为止休眠的时间 + gc 时间超过)使用clock_nanosleep() 休眠直到给定时间戳:

struct timespec req;
if (clock_gettime(CLOCK_MONOTONIC, &req) < 0) {
  perror("clock_gettime");
  exit(EXIT_FAILURE);
}
req.tv_sec += 100;
int rc;
while ((rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &req, NULL)) != 0) {
  if (rc != EINTR) {
     fprintf(stderr, "clock_nanosleep: %s\n", strerror(rc));
     exit(EXIT_FAILURE);
  }
}

【讨论】:

    猜你喜欢
    • 2014-01-22
    • 1970-01-01
    • 1970-01-01
    • 2011-10-17
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多