【问题标题】:Segmentation Fault - pthread mutex locking issue分段错误 - pthread 互斥锁问题
【发布时间】:2017-01-31 09:32:56
【问题描述】:

我正在创建一个简单的 kdb+ 共享库,它在单独的线程上生成值并在数据准备好时执行回调函数。应用程序正在新线程中将数据写入文件描述符,并在主事件循环中从中读取。尝试锁定和解锁互斥锁时,应用程序似乎出现了段错误。

如果我在循环中引入一个小睡眠,段错误似乎消失了。这表明pthread_mutex_lock 调用不会阻塞线程,直到我预期的那样获得锁。

#include <k.h>
#include <pthread.h>
#include <time.h>

#define PIPE_CAPACITY 65536

static int fd;
static pthread_t thread;
static pthread_mutex_t lock;

K callback(int d)
{
    K data;

    // Aquire mutex lock and read from fd
    pthread_mutex_lock(&lock);
    read(d, &data, PIPE_CAPACITY);
    pthread_mutex_unlock(&lock);

    // kdb+ callback
    k(0, (char *)"callback", r1(data), (K)0);

    return (K)0;
}

void* loop()
{
    while (1) {
        struct timespec ts;
        struct tm *time;

        // Get seconds and nanoseconds since epoch
        clock_gettime(CLOCK_REALTIME, &ts);

        // Adjust for kdb+
        time = gmtime(&ts.tv_sec);
        time->tm_sec = 0;
        time->tm_min = 0;
        time->tm_hour = 0;
        ts.tv_sec -= mktime(time); // Subtract seconds between epoch and midnight

        // Create kdb+ timestamp
        K data = ktj(-KN, ts.tv_sec * 1000000000 + ts.tv_nsec);

        // Aquire mutex lock and write to fd
        pthread_mutex_lock(&lock);
        write(fd, &data, sizeof(K));
        pthread_mutex_unlock(&lock);
    }
}

K init()
{
    // Initialize mutex
    pthread_mutex_init(&lock, NULL);

    // Create file descriptor
    fd = eventfd(0, 0);

    // Register callback
    sd1(fd, callback);

    // Launch thread
    pthread_create(&thread, NULL, loop, NULL);
}

【问题讨论】:

  • 不相关,但您确实应该避免使用一个字母的类型名称,例如K
  • 能否提供“main”功能?初始化是否在线程创建前生效?
  • @MichaelWalz 这取决于我必须使用的 API,而不是我个人的选择 - 包含在 k.h
  • @Emisilve86 这是一个共享库,没有主函数。入口点将是init
  • @AnthonyGraham Fyi,gmtime 不是线程安全的。如果在您的平台上提供,您应该使用gmtime_r(这很有可能,因为您正在使用线程)。或者 gmtime_s 如果使用符合 C11 的工具链。

标签: c multithreading pthreads mutex kdb


【解决方案1】:

回想一下,K 是在 k.h 中定义的指针类型:

typedef struct k0{..}*K;

这意味着您将一个指向在“循环”线程中创建的对象的指针发送到在主线程中执行的回调。这不起作用,因为 kdb+ 为每个线程使用单独的内存拉取。我建议改为传递数据的副本。

另一个问题出在这条线上

read(d, &data, PIPE_CAPACITY);

您正在读取 65536 个字节,但将 8 字节变量的地址作为目标传递。引入延迟时没有出现段错误的原因是,在这种情况下,循环没有机会在两次读取之间写入超过 8 个字节。

最后,我不确定是否可以将 eventfd 返回的文件描述符用作读写缓冲区。我建议使用旧的 pipe() 调用。

您的代码的以下修改适用于我:

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

static int fd[2];
static pthread_t thread;
static pthread_mutex_t lock;

K callback(int d)
{
    K data = ktj(-KN, 0);

    // Aquire mutex lock and read from fd
    pthread_mutex_lock(&lock);
    read(d, (void *)&data->j, sizeof(data->j));
    pthread_mutex_unlock(&lock);

    // kdb+ callback
    k(0, (char *)"callback", data, (K)0);

    return (K)0;
}

void* loop()
{
    while (1) {
        struct timespec ts;
        struct tm *time;

        // Get seconds and nanoseconds since epoch
        clock_gettime(CLOCK_REALTIME, &ts);

        // Adjust for kdb+
        time = gmtime(&ts.tv_sec);
        time->tm_sec = 0;
        time->tm_min = 0;
        time->tm_hour = 0;
        ts.tv_sec -= mktime(time); // Subtract seconds between epoch and midnight

        // Create kdb+ timestamp
        J data = (J)ts.tv_sec * 1000000000 + ts.tv_nsec;

        // Aquire mutex lock and write to fd
        pthread_mutex_lock(&lock);
        write(fd[1], &data, sizeof(data));
        pthread_mutex_unlock(&lock);
    }
}

K1(init)
{
    // Initialize mutex
    pthread_mutex_init(&lock, NULL);

    // Create file descriptor
    pipe(fd);

    // Register callback
    sd1(fd[0], callback);

    // Launch thread
    pthread_create(&thread, NULL, loop, NULL);

    R ktj(0, 0);
}

为了测试,把上面的代码复制到x.c中,编译

$ gcc -Wall -shared -fPIC -I $(pwd) -DKXVER=3 x.c -o x.so

并运行以下q代码:

callback:0N!
init:`:./x 2:(`init;1)
init[]

【讨论】:

  • read(d, (void *)&amp;data-&gt;j, sizeof(data-&gt;j)); yessssssssssssssssss。就是这样,您在此声明中认真地帮助了我,非常感谢您... ......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 2013-06-06
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 2012-06-06
相关资源
最近更新 更多