3

我有两个线程,在 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 );
}
4

2 回答 2

4

这是从您的第一个版本派生的 - 它有点简单。

话题一:作家

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);

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

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

于 2009-03-03T18:30:19.390 回答
3

第一个版本是正确的,写入和读取都需要互斥锁。

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

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

于 2009-03-03T17:49:53.683 回答