gpt4 book ai didi

c - C 中的读取器/写入器实现

转载 作者:行者123 更新时间:2023-11-30 14:49:10 25 4
gpt4 key购买 nike

我目前正在大学学习并发。在这种情况下,我必须用 C 实现读取器/写入器问题,我认为我走在正确的轨道上。

我对这个问题的想法是,我们需要两个锁rd_lockwr_lock。当编写器线程想要更​​改全局变量时,它会尝试获取两个锁,写入全局变量并解锁。当读取器想要读取全局时,它会检查 wr_lock 当前是否已锁定,然后读取该值,但是其中一个读取器线程应该获取 rd_lock,但是其他读者不应该关心 rd_lock 是否被锁定。

我不允许使用 pthread 库中已有的实现。

typedef struct counter_st {
int value;
} counter_t;

counter_t * counter;
pthread_t * threads;

int readers_tnum;
int writers_tnum;

pthread_mutex_t rd_lock;
pthread_mutex_t wr_lock;

void * reader_thread() {

while(true) {
pthread_mutex_lock(&rd_lock);
pthread_mutex_trylock(&wr_lock);
int value = counter->value;
printf("%d\n", value);
pthread_mutex_unlock(&rd_lock);
}
}

void * writer_thread() {

while(true) {
pthread_mutex_lock(&wr_lock);
pthread_mutex_lock(&rd_lock);

// TODO: increment value of counter->value here.
counter->value += 1;

pthread_mutex_unlock(&rd_lock);
pthread_mutex_unlock(&wr_lock);
}
}

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

readers_tnum = atoi(args[1]);
writers_tnum = atoi(args[2]);

pthread_mutex_init(&rd_lock, 0);
pthread_mutex_init(&wr_lock, 0);

// Initialize our global variable
counter = malloc(sizeof(counter_t));
counter->value = 0;

pthread_t * threads = malloc((readers_tnum + writers_tnum) * sizeof(pthread_t));
int started_threads = 0;

// Spawn reader threads
for(int i = 0; i < readers_tnum; i++) {
int code = pthread_create(&threads[started_threads], NULL, reader_thread, NULL);

if (code != 0) {
printf("Could not spawn a thread.");
exit(-1);
} else {
started_threads++;
}
}

// Spawn writer threads
for(int i = 0; i < writers_tnum; i++) {
int code = pthread_create(&threads[started_threads], NULL, writer_thread, NULL);

if (code != 0) {
printf("Could not spawn a thread.");
exit(-1);
} else {
started_threads++;
}
}
}

目前,当使用 1 个读取器和 1 个写入器运行时,它仅打印大量零,这意味着它从未真正执行写入器线程中的代码。我知道这对于多个读者来说不会按预期工作,但是我不明白当每个读者都运行它时出了什么问题。

最佳答案

不要将锁视为“读取器锁”和“写入器锁”。

因为您需要允许多个并发读取器,所以读取器不能持有互斥体。 (如果它们这样做,它们就会被序列化;只有一个可以同时持有互斥锁。)它们可以在短时间内(开始访问之前和结束访问之后)使用一个互斥锁来更新状态,但那就是它。

将拥有 rwlock 的时间线分为三个部分:“获取 rwlock”“执行工作”“释放 rwlock”

例如,您可以使用一个互斥体、一个条件变量和一个计数器。计数器保存活跃读者的数量。条件变量由最后一个读取器和写入器在释放互斥体之前发出信号,以唤醒等待的写入器。互斥量保护两者,并由写入者在其写入操作的整个持续时间内持有。

所以,在伪代码中,你可能有

Function rwlock_rdlock:
Take mutex
Increment counter
Release mutex
End Function

Function rwlock_rdunlock:
Take mutex
Decrement counter
If counter == 0, Then:
Signal_on cond
End If
Release mutex
End Function

Function rwlock_wrlock:
Take mutex
While counter > 0:
Wait_on cond
End Function

Function rwlock_unlock:
Signal_on cond
Release mutex
End Function

请记住,每当您等待条件变量时,互斥锁都会在等待期间以原子方式释放,并在线程唤醒时自动获取。因此,为了等待条件变量,线程在等待之前和之后都将拥有互斥锁,但在等待期间则不会。

现在,上述方法并不是您可以实现的唯一方法。

特别是,您可能会注意到,在上述方案中,您必须使用不同的“解锁”操作,具体取决于您对 rwlock 进行读锁定还是写锁定。在 POSIX pthread_rwlock_t 实现中,只有一个 pthread_rwlock_unlock()

无论你设计什么方案,重要的是检查它是否在所有情况下都能正常工作:一个单独的读锁定器、一个单独的写锁定器、多个读锁定器、多个写锁定器、一个单独的写锁定器。锁定器和一个读取锁定器、一个单独的写入锁定器和多个读取锁定器、多个写入锁定器和一个单独的读取锁定器、以及多个读取和写入锁定器。

例如,让我们考虑这样的情况:有多个事件读取器,并且写入器想要对 rwlock 进行写锁定。

作者获取互斥体。然后它注意到计数器不为零,因此它开始等待条件变量。当最后一个读者时 - 请注意读者退出的顺序并不重要,因为使用了一个简单的计数器! -- 解锁 rwlock 上的读锁,它在条件变量上发出信号,这会唤醒写入器。然后,编写者获取互斥体,看到计数器为零,然后继续执行其工作。在此期间,互斥体由写入者持有,因此所有新的读取者都会阻塞,直到写入者释放互斥体。因为写入程序在释放互斥锁时也会向条件变量发出信号,所以这是其他等待写入程序和等待读取程序之间的竞争,谁先执行。

关于c - C 中的读取器/写入器实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49836108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com