【问题标题】:pthread read-write lock indefinite behaviourpthread 读写锁定无限期行为
【发布时间】:2016-01-14 11:50:54
【问题描述】:

我在测试 pthread 读写锁时遇到了意想不到的结果。

以下是我的代码。

#include <iostream>
#include <thread>
#include <pthread.h>

//locks declaration
pthread_rwlock_t       rwlock;

//shared resource
int numbers[20];
int size = 0;


void readFrom()
{
    int rc;

    rc = pthread_rwlock_rdlock(&rwlock);

    for(int index = 0; index < size; index++) {
    std::cout << numbers[index] <<  " ";
    }    
    std::cout << std::endl;

    rc = pthread_rwlock_unlock(&rwlock);
}

void writeTo(int index, int val)
{
    int rc;

    rc = pthread_rwlock_wrlock(&rwlock);

    numbers[index] = val;

    size++;

    rc = pthread_rwlock_unlock(&rwlock);

}

int main(int argc, char **argv)
{
    int rc=0;
    std::cout << std::endl;
    std::thread threads[25];

    rc = pthread_rwlock_init(&rwlock, NULL);

    for(int i=0; i<20; ++i) {
    threads[i] = std::thread(writeTo, i, i);
    if(i % 5 == 0) {
        threads[20 + (i / 5)] = std::thread(readFrom);
        }
    } 



    for(int i=0; i<24; ++i) {
    threads[i].join();

    }



    std::cout << "size is " << size << std::endl;


    threads[24] = std::thread(readFrom);
    threads[24].join();
    std::cout << std::endl;



    rc = pthread_rwlock_destroy(&rwlock);
    return 0;
}

经过几次运行,我偶尔会发现一些意想不到的事情。这是一个例子:

0 1 2 3 0

它是读取器线程的输出。基本上,它说数字的大小现在是 5。在这种情况下,我希望结果应该是 0 1 2 3 4。

顺便说一句,我尝试实现加法互斥锁,这会引发意想不到的行为。

我对解决方案和根本原因都很感兴趣。谁能帮帮我?

提前感谢任何帮助。

【问题讨论】:

  • 您的惊讶似乎源于编写器线程按顺序执行的期望。在没有明确同步的情况下,他们为什么要这样做?
  • 你能解释一下为什么你认为结果应该是“0 1 2 3 4”吗?您认为具体是什么阻止了“0 1 2 3 0”的结果? (如果你有四个核心,这正是我所期望的。)
  • 抱歉回复晚了。我的 CPU 模块是英特尔酷睿™ i7-5500u 处理器。我在网上查看了声称核心数为 2 的英特尔规范。但是,我执行了“lscpu”,这表明有 4 个处理器。我认为这个结果没有任何意义。此外,我曾尝试使用互斥锁实现强制排序,但正如我所提到的,它变得更糟了。我想被喂饱:)
  • @Bill 你有两个物理核心和四个虚拟核心。
  • @DavidSchwartz 你能告诉我为什么我们应该期待“0 1 2 3 0”的结果。即使在查看 pthread 标头中 pthread_rwlock 的规范后,我也对此感到困惑。

标签: c++ pthreads readwritelock


【解决方案1】:

读取器/写入器锁只是防止两个写入器同时运行或一个写入器作为读取器同时运行。获得输出“0 1 2 3 0”不需要这些东西。所以你没有理由认为这是意外的。

事实上,如果您有四个内核,那么“0 1 2 3 0”肯定是我至少在某些时候期望的输出。线程按照它们启动的顺序运行,直到所有四个内核都在使用中,然后新线程必须等到现有线程完成它们的时间片。这在我看来是完全合理的。

如果您能详细说明让您认为“0 1 2 3 0”出乎意料的思维过程,我们可以指出其中的具体缺陷。

顺便说一下,对于这样的应用程序,您应该只使用常规锁。仅当读取器操作明显多于写入操作或读取器需要持有锁的时间相对较长时,使用读取器/写入器锁才有意义。

【讨论】:

  • 感谢您对我的疑惑的详尽解释。事实上,这段代码是为了和我自己实现的读/写锁机制进行比较。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 2017-04-06
  • 1970-01-01
相关资源
最近更新 更多