Назад | Перейти на главную страницу

высокая загрузка ЦП из-за pthread_cond_wait или nanosleep

Прежде всего, я поискал на stackoverflow.com и погуглил, но эффективных результатов не нашел.

Мой вопрос: почему pthread_cond_wait потребляет столько ресурсов процессора? Не думаю, что это нормально.

Моя программа страдала от того, что% CPU периодически становился высоким и оставался высоким более десяти секунд. Когда% CPU был стабильно низким, он был около 1. Когда он стал высоким, он был между 50 и 300.

Я использовал top -H -p, чтобы найти единственный поток, потребляющий больше всего ЦП, когда% ЦП процесса стал высоким, а затем я использовал strace -T -r -c -p, чтобы найти дополнительную информацию:

strace -T -r -c -p 1701

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 88.54    0.482646          43     11157      3020 futex
  9.85    0.053682           0    131052           read
  1.50    0.008192          38       213           nanosleep
  0.04    0.000214           1       239           write
  0.03    0.000154           1       213           open
  0.02    0.000111           1       213           munmap
  0.02    0.000085           0       239           stat
  0.01    0.000044           0       213           mmap
  0.00    0.000018           0       213           close
  0.00    0.000000           0       213           fstat
  0.00    0.000000           0       213           lseek
------ ----------- ----------- --------- --------- ----------------
100.00    0.545146                144178      3020 total

И стек этого потока:

Тема 6 (Тема 0x7f1404f41700 (LWP 1701)):

#0  0x0000003d6f60b63c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x0000000000406045 in foo(void*) ()
#2  0x0000003d6f607a51 in start_thread () from /lib64/libpthread.so.0
#3  0x0000003d6eee893d in clone () from /lib64/libc.so.6

И связанный фрагмент кода:

static std::deque<std::string> conveyor;
static pthread_mutex_t conveyor_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t conveyor_cond = PTHREAD_COND_INITIALIZER;

#define POP_NUM 4

static void *foo(void *arg)
{
    write_log(LOG_INFO, "thread foo created");

    int ret = pthread_detach(pthread_self());
    if (ret != 0) {
        write_log(LOG_ERR, "pthread_detach[foo] failed with errno[%d]", ret);
        write_log(LOG_ERR, "thread foo exiting");
        return (void *)-1;
    }

    std::string paths[POP_NUM], topic;
    int n;

    do {
        if ((ret = pthread_mutex_lock(&conveyor_mtx)) != 0) {
            write_log(LOG_WARNING, "pthread_mutex_lock[conveyor_mtx] failed"
                      " with errno[%d]", ret);
            sleep(1);
            continue;
        }
        while (conveyor.empty()) {
            write_log(LOG_INFO, "conveyor empty");
            pthread_cond_wait(&conveyor_cond, &conveyor_mtx);
        }
        for (n = 0; n < POP_NUM; n++) {
            paths[n].assign(conveyor.front());
            conveyor.pop_front();
            if (conveyor.empty()) break;
        }
        if ((ret = pthread_mutex_unlock(&conveyor_mtx)) != 0) {
            write_log(LOG_WARNING, "pthread_mutex_unlock[conveyor_mtx] failed"
                      " with errno[%d]", ret);
        }
        for (int i = 0; i < n; i++) {
            if (!extract_topic_from_path(paths[i], topic)) continue;
            produce_msgs_and_save_offset(topics[topic],
                                      const_cast<char *>(paths[i].c_str()));
        }
    } while (true);

    write_log(LOG_ERR, "thread foo exiting");

    return (void *)0;
}

static void *bar(void *arg)
{
    write_log(LOG_INFO, "thread bar created");

    int inot_fd = (int)(intptr_t)arg, n, ret;
    struct pollfd pfd = { inot_fd, POLLIN | POLLPRI, 0 };

    do {
        //n = poll(&pfd, 1, -1);
        //n = poll(&pfd, 1, 300000);
        n = poll(&pfd, 1, 120000);
        if (n == -1) {
            if (errno == EINTR) {
                write_log(LOG_WARNING, "poll interrupted by a signal");
                continue;
            }
            write_log(LOG_ERR, "poll failed with errno[%d]", errno);
            write_log(LOG_ERR, "thread bar exiting");
            return (void *)-1;
        } else if (n == 0) {
            write_log(LOG_WARNING, "poll timed out after 120 seconds");
            sleep(60);
        }

        int i;
        for (i = 0; i < 3; i++) {
            if ((ret = pthread_mutex_lock(&conveyor_mtx)) != 0) {
                write_log(LOG_WARNING, "pthread_mutex_lock[conveyor_mtx] failed"
                          "[%d] with errno[%d]", i, ret);
                continue;
            } else {
                break;
            }
        }
        if (i == 3) {
            write_log(LOG_ERR, "thread bar exiting");
            return (void *)-1;
        }
        if ((n = baz(inot_fd)) > 0) {
            pthread_mutex_unlock(&conveyor_mtx);
            pthread_cond_broadcast(&conveyor_cond);
        } else if (n == 0) {
            pthread_mutex_unlock(&conveyor_mtx);
        } else {
            pthread_mutex_unlock(&conveyor_mtx);
            pthread_cond_broadcast(&conveyor_cond);
            write_log(LOG_ERR, "thread bar exiting");
            return (void *)-1;
        }

        if ((n = poll_producer(producer, 1000, 2)) > 0) {
            write_log(LOG_INFO, "rdkafka poll events[%d] of producer"
                      " for possible big outq size", n);
        }
    } while (true);

    write_log(LOG_ERR, "thread bar exiting");

    return (void *)0;
}

Более того, если бы я не использовал pthread_cond_wait / pthread_cond_broadcast и заменил «pthread_cond_wait» в приведенном выше фрагменте на «sleep», strace показал бы, что самым дорогостоящим системным вызовом был nanosleep.

uname -a Linux d144122 2.6.32-358.el6.x86_64 # 1 SMP Пт 22 февраля, 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux

У меня была эта проблема с ядром, в котором не было поддержки системного вызова futex.

Соответствующий параметр ядра - CONFIG_FUTEX. Убедитесь, что ваше ядро ​​было собрано с этой опцией (чаще всего).

Тот факт, что ваш вывод strace показывает так много ошибок futex, заставляет меня сильно подозревать, что это проблема.

(Я знаю, что этот вопрос довольно старый, но это была неприятная проблема, и я хотел задокументировать решение для других бедных заблудших душ)

Я была такая же проблема. В моем случае это было вызвано использованием #pragma pack, как в этой ветке: https://stackoverflow.com/questions/22166474/pthread-cond-wait-doesnt-make-cpu-sleep

Удаление пачки решило мою проблему ...