【问题标题】:How do I read/write a shared variable with pthreads?如何使用 pthread 读取/写入共享变量?
【发布时间】:2010-10-11 01:53:35
【问题描述】:

我有两个线程,在 linux 上使用 C pthreads。其中一个写入数据,另一个正在读取数据。我正在使用一个变量来允许读取线程何时允许读取并允许写入线程。所以互斥锁适用于这个名为“newData”的布尔变量。我的问题是:我是否需要在“if”条件内锁定/解锁访问周围的互斥锁?两种方式都有效,但我认为只是因为在这个变量上重叠写/读的机会很少。我展示了这两种选择来更好地解释我的问题:

线程 1:

pthread_mutex_lock( &lattice_mutex );
if (!newData) {
    pthread_mutex_unlock( &lattice_mutex );
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

线程 2:

pthread_mutex_lock( &lattice_mutex );
if(newData) {
    pthread_mutex_unlock( &lattice_mutex );
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
} else {
    pthread_mutex_unlock( &lattice_mutex );
}

第二个版本,可行但不知道是否正确:

线程 1:

if (!newData) {
    uchar *lattice_pos = lattice;
    int i;
    for(i=0; i<size; i++) {
        *lattice_pos = rand()%CHAR_MAX;
        lattice_pos++;
    }
    pthread_mutex_lock( &lattice_mutex );
    newData = TRUE;
    pthread_mutex_unlock( &lattice_mutex );
}

线程 2:

if(newData) {
    renderUpdate();
    pthread_mutex_lock( &lattice_mutex );
    newData = FALSE;
    pthread_mutex_unlock( &lattice_mutex );
}

【问题讨论】:

  • 简单地说,标准说如果你想访问一个变量,而另一个线程正在或可能正在修改它,你需要一个互斥锁。您可能具有允许您避免这种情况的特定于平台的功能(例如原子操作),但是在所有访问周围使用互斥锁是保证在所有平台上工作的方式。

标签: c pthreads


【解决方案1】:

第一个版本是正确的,您需要在写入和读取时使用互斥锁。

但是,AFAIK,几乎所有的架构都具有对一个数据单元(例如 int)原子的简单读写访问。但是,请注意,在内存排序较弱的架构上,您可能会遇到问题,例如在缓冲区实际包含数据之前看到“缓冲区满”标志为真。

请注意,代码可能不是您能做的最好的,因为它从不休眠(使用忙等待)。如果您想在任一线程中等待数据,则必须将条件变量与互斥锁一起使用。

【讨论】:

  • 感谢您的回答!我想我没有完全理解最后一段。我的 2 个线程一直在工作,即使如果条件不满足,它们可能不会执行“if”内的函数。即使他们继续工作,使用 sleep() 是否正确?我没用过:|
  • 如果您的线程一直在做一些工作,并且永远不必等待其他线程填充/清空缓冲区(例如游戏中的绘图代码),您可以忽略关于睡觉的部分。此外,即使您确实需要睡觉,使用 sleep() 也几乎总是错误的,
【解决方案2】:

这是从您的第一个版本派生的 - 它稍微简单一些。

线程 1:作家

pthread_mutex_lock(&lattice_mutex);
if (!newData) {
    pthread_mutex_unlock(&lattice_mutex);  // Omit?
    uchar *lattice_pos = lattice;
    int i;
    for (i = 0; i < size; i++)
        *lattice_pos++ = rand() % CHAR_MAX;
    pthread_mutex_lock(&lattice_mutex);   // Omit?
    newData = TRUE;
}
pthread_mutex_unlock(&lattice_mutex);

线程 2:阅读器

pthread_mutex_lock(&lattice_mutex);
if (newData) {
    pthread_mutex_unlock(&lattice_mutex);   // Omit?
    renderUpdate();
    pthread_mutex_lock(&lattice_mutex);     // Omit?
    newData = FALSE;
}
pthread_mutex_unlock(&lattice_mutex);

这取决于晶格信息的确切使用方式,但鉴于互斥体的名称,我认为在修改晶格时应该将其锁定,因此有两对线标记为“省略?”应该被删除。否则,格不会受到并发访问的保护。

补充:我认为第二个版本是错误的 - 它没有正确保护晶格。

【讨论】:

  • 谢谢!它实际上更简单...... :)
  • @Alvaro:你是说这是一个准确的评估吗?那些标有“省略”的行?可以省略吗?
  • 可以省略。实际上是最简单和最好的解决方案。但是,我不得不使用 newData 变量,否则性能真的很差。我不知道具体原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多