pthread_cond_timedwait() 不适用于 FreeBSD,returns EPERM

pthread_cond_timedwait() not working on FreeBSD, returns EPERM

我有一个创建 pthread 的示例程序,等待线程加入。线程将调用 phread_cond_timedwait() 等待 2 秒。在 Linux 平台上,示例代码运行良好。在 FreeBSD 上,调用 returns 立即出现 EPERM 错误代码。

pthread_condition_timedwait.cpp

#define _BSD_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>

void *thread_handler(void *ptr){
  pthread_cond_t cond  = PTHREAD_COND_INITIALIZER;
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  struct timespec ts;
  struct timeval tp;

  gettimeofday(&tp, NULL);

  ts.tv_sec  = tp.tv_sec;
  ts.tv_nsec = tp.tv_usec*1000;
  ts.tv_sec += 2;

  //Invoke pthread_cond_timedwait() to wait for 2 seconds
  int rcode = pthread_cond_timedwait(&cond, &mutex, &ts);

  if (rcode == ETIMEDOUT)
    printf("Terminated due to time out\n");
  else if (rcode == EPERM)
    printf("Terminated due to EPERM\n");
  else
    printf("Return code is %d\n", rcode);

  return NULL;
}


int main(int argc, char** argv){
  pthread_t thread;

  // start the thread
  pthread_create(&thread, NULL, &thread_handler, NULL);

  // wait for thread to finish
  pthread_join(thread, NULL);
  return 0;
}

如果调用 timedwait 的线程不拥有互斥锁,则返回 EPERM。您必须在调用 timedwait 之前锁定互斥量。此外,将 mutex 和 condvar 的静态初始化移动到文件范围。

更新:如果将互斥锁初始化为错误检查互斥锁,Linux 也将以 EPERM 终止(因为在不持有互斥锁的情况下调用 pthread_cond_wait/timedwait 是 UB)。

修改后的代码如下:

//#define _BSD_SOURCE                                                                                                                                                                                                                                                                     

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex;


void *thread_handler(void *ptr){

    struct timespec ts;
    struct timeval tp;

    gettimeofday(&tp, NULL);

    ts.tv_sec  = tp.tv_sec;
    ts.tv_nsec = tp.tv_usec*1000;
    ts.tv_sec += 2;

    //Invoke pthread_cond_timedwait() to wait for 2 seconds                                                                                                                                                                                                                               
    int rcode = pthread_cond_timedwait(&cond, &mutex, &ts);

    if (rcode == ETIMEDOUT)
        printf("Terminated due to time out\n");
    else if (rcode == EPERM)
        printf("Terminated due to EPERM\n");
    else
        printf("Return code is %d\n", rcode);

    return NULL;
}

int main(int argc, char** argv){

    pthread_mutexattr_t mta;
    pthread_mutexattr_init(&mta);
    pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);

    pthread_mutex_init(&mutex, &mta);

    pthread_t thread;

    // start the thread                                                                                                                                                                                                                                                                   
    pthread_create(&thread, NULL, &thread_handler, NULL);

    // wait for thread to finish                                                                                                                                                                                                                                                          
    pthread_join(thread, NULL);
    return 0;
}

在内核 SMP Debian 4.9.82-1+deb9u3 (2018-03-02) x86_64 GNU/Linux, distro Debian GNU/Linux buster/sid.