并发队列,C

时间:2011-05-12 07:17:56

标签: c concurrency

所以,我正在尝试在C中实现并发队列。我已将方法拆分为“读取方法”和“写入方法”。因此,当访问write方法(如push()和pop())时,我获取了一个写入器锁。对于读取方法也是如此。此外,我们可以有几个读者,但只有一个作家。

为了让它在代码中工作,我有一个整个队列的互斥锁。还有两个条件锁 - 一个用于作者,另一个用于读者。我还有两个整数来跟踪当前使用队列的读者和作者的数量。

所以我的主要问题是 - 如何实现多个读者同时访问读取方法?

目前这是我的一般读取方法代码:(在伪代码中 - 而不是C.我实际上正在使用pthreads。)

mutex.lock();
while (nwriter > 0) {
  wait(&reader);
  mutex.unlock();
}
nreader++;
//Critical code
nreader--;
if (nreader == 0) {
  signal(&writer)
}
mutex.unlock

所以,想象一下,我们有一个持有互斥锁的读者。现在任何其他读者,并尝试获取互斥锁,将无法。不会阻止吗?那么许多读者如何同时访问读取方法呢?

我的推理是否正确?如果是,如何解决问题?

4 个答案:

答案 0 :(得分:2)

如果不是练习,请使用pthreads(pthread_rwlock_*函数)的读写锁。

另请注意,使用lock stil保护单个调用可能无法提供必要的正确性保证。例如,从STL队列中弹出元素的典型代码是

if( !queue.empty() ) {
    data = queue.top();
    queue.pop();
}

即使在队列方法中使用了锁,这也会在并发代码中失败,因为从概念上讲,此代码必须是原子事务,但实现不提供此类保证。线程可以弹出与top()读取的元素不同的元素,或尝试从空队列等弹出

答案 1 :(得分:1)

请找到以下读/写功能。

在我的函数中,我使用了canRead和canWrite互斥体和nReads来获取读者数量:

写功能:

lock(canWrite) // Wait if mutex if not free
// Write
unlock(canWrite)

阅读功能:

lock(canRead) // This mutex protect the nReaders
nReaders++    // Init value should be 0 (no readers)
if (nReaders == 1) // No other readers
{
   lock(canWrite)  // No writers can enter critical section
}
unlock(canRead)

// Read

lock(canRead)
nReaders--;
if (nReaders == 0) // No more readers
{
   unlock(canWrite) // Writer can enter critical secion
}
unlock(canRead)

答案 2 :(得分:0)

经典的解决方案是多读者,单一作家。

数据结构始于没有读者和没有作者。

您允许任意数量的并发读者。

当一位作家出现时,你阻止他直到所有现在的读者完成;那么你就让他走了(任何新的读者和作家都会按顺序在他身后排队。)

答案 3 :(得分:0)

您可以尝试使用内置于c本机,无锁,适用于跨平台lfqueue的库

例如:-

int* int_data;
lfqueue_t my_queue;

if (lfqueue_init(&my_queue) == -1)
    return -1;

/** Wrap This scope in other threads **/
int_data = (int*) malloc(sizeof(int));
assert(int_data != NULL);
*int_data = i++;
/*Enqueue*/
 while (lfqueue_enq(&my_queue, int_data) == -1) {
    printf("ENQ Full ?\n");
}

/** Wrap This scope in other threads **/
/*Dequeue*/
while  ( (int_data = lfqueue_deq(&my_queue)) == NULL) {
    printf("DEQ EMPTY ..\n");
}

// printf("%d\n", *(int*) int_data );
free(int_data);
/** End **/

lfqueue_destroy(&my_queue);