【问题标题】:C Segmentation Fault - readers and writersC 分段错误 - 读取器和写入器
【发布时间】:2018-01-18 02:55:40
【问题描述】:

我正在尝试在 C 中实现读取器和写入器问题的变体,不同之处在于写入器可以是增量器或减量器,并且它们应该保持运行计数。下面是我尝试实现的代码,我收到错误“分段错误(核心转储)。我尝试调试并从 gdb 收到此反馈 - #0 0x0000000000400d84 in main ()。 如果有人能够向我解释/给我有关如何解决此故障的提示,我将不胜感激。 谢谢!

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

#define WAIT 20
#define NEW 0

#define DECREMENT 0
#define INCREMENT 1

#define TIME 5
#define VALUE 1
#define COMMON 0


int readerCount = NEW;
int total = 0;
int v;
sem_t mutex;
sem_t access_data;



int increment_or_decrement() {
    int d;
    return d = rand() % 2;
}

void *writer(void *arg) {
    int version = increment_or_decrement();

    int *iID = (int *) arg;
    int *dID = (int *) arg;

    sleep(rand() % WAIT);

    sem_wait(&access_data);

    if (version == INCREMENT) {
        fprintf(stderr, "Incrementer %d accessed the data\n", *iID);
        total++;
        fprintf(stderr, "Total: %d\n", total);
    }
    else {
        fprintf(stderr, "Decrementer %d accessed the data\n", *dID);
        total--;
        fprintf(stderr, "Total: %d\n", total);
    }

    sleep(TIME);

    sem_post(&access_data);

    pthread_exit(NULL);

}


void *reader(void *arg) {
    int *id = (int *) arg;

    sleep(rand() % WAIT);

    while(1) {
        if (readerCount == NEW) {
            sem_wait(&mutex);

            v = version;
            readerCount++;

            if (readerCount == 1)
                sem_wait(&access_data);

            sem_post(&mutex);

            fprintf(stderr, "Reader %d accessed the data\n", *id);

            sem_wait(&mutex);

            readerCount--;

            if(readerCount == NEW)
                sem_post(&access_data);

            sem_post(&mutex);

            pthread_exit(NULL);
        }
    }

}


int main() {
    int numReaders = rand();
    int numWriters = rand();
    int i;

    sem_init(&mutex, COMMON, VALUE);
    sem_init(&access_data, COMMON, VALUE);

    pthread_t readers[numReaders];
    pthread_t writers[numWriters];

    int readerID[numReaders];
    int writerID[numWriters];

    for (i = 0; i < numReaders; i++)
        readerID[i] = i;

    for (i = 0; i < numWriters; i++)
        writerID[i] = i;

    for (i = 0; i < numReaders; i++) {
        if(pthread_create(&readers[i], NULL, reader, (void *) &readerID[i]) != 0) {
            printf("Child failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numWriters; i++) {
        if (pthread_create(&writers[i], NULL, writer, (void *) &writerID[i]) != 0) {
            printf("Child failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numReaders; i++) {
        if (pthread_join(readers[i], NULL) != 0) {
            printf("Join failed\n");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < numWriters; i++) {
        if (pthread_join(writers[i], NULL) != 0) {
            printf("Join failed\n");
            exit(EXIT_FAILURE);
        }
    }

    sem_destroy(&access_data);
    sem_destroy(&mutex);
}

【问题讨论】:

  • rand() 可以返回一个相当大的数字。然而,这就是您用于线程数和数组大小的东西,坦率地说,这很疯狂。也许您应该将其限制在合理的范围内,包括 > 0 且小于 8 的值。而且,您还可以在线程上使用 rand(),这是出了名的 not 线程-安全。

标签: c segmentation-fault pthreads semaphore readerwriterlock


【解决方案1】:

嫌疑人:pthread_join(readers[i], NULL)

pthread_join 的第二个参数应该是 var 的有效地址,以包含来自现有子线程的返回值的地址。在这种情况下,当子线程退出时,pthread_exit 会尝试将 NULL 写入 NULL,我认为这会导致 seg 错误。尝试将 NULL 更改为 pthread_join 中对读写器都有效的地址,看看它是否有效。

编辑:事实证明,POSIX 允许将 NULL 传递给 pthread_join(参见下面的 cmets),因此嫌疑人被无罪释放。

【讨论】:

  • pthread_join() 的 POSIX 规范允许第二个参数为空指针,在这种情况下不返回任何值。这种用法是允许的。
  • 谢谢@JonathanLeffler,你是对的。会不会是 RAND_MAX > PTHREAD_THREADS_MAX ,所以 pthread_create 出错了?
【解决方案2】:

如果 rand 返回 @WhozCraig 在 cmets 中指示的大数字,您可能会用完堆栈空间

如果你只是分配一些有限的值而不是在这里使用 rand:

  int numReaders = rand();
  int numWriters = rand();

我看到它在没有分段错误的情况下运行

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 2013-03-15
    相关资源
    最近更新 更多