Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 是否可以创建一个线程安全的队列,同时执行推送和弹出操作?_C_Multithreading - Fatal编程技术网

C 是否可以创建一个线程安全的队列,同时执行推送和弹出操作?

C 是否可以创建一个线程安全的队列,同时执行推送和弹出操作?,c,multithreading,C,Multithreading,这更像是一个理论问题,而不是一个有用的问题,但我想不出一个方法来做到这一点。需要明确的是,目标是创建一个队列,允许多个线程同时推送和弹出,而不会相互阻塞 目标的一个例子是: 螺纹A推两次。线程A和线程B调用push,线程C和线程D调用pop。线程A获取队列位置2,线程B获取队列位置3,线程C获取队列位置0,线程D获取队列位置1。所有线程都能够同时读取/写入各自的位置 这些推送和弹出功能可以做到这一点,但不是线程安全的: #包括 #包括 ... 作废推送(作废*项){ sem_wait(推送可用性

这更像是一个理论问题,而不是一个有用的问题,但我想不出一个方法来做到这一点。需要明确的是,目标是创建一个队列,允许多个线程同时推送和弹出,而不会相互阻塞

目标的一个例子是: 螺纹A推两次。线程A和线程B调用
push
,线程C和线程D调用
pop
。线程A获取队列位置2,线程B获取队列位置3,线程C获取队列位置0,线程D获取队列位置1。所有线程都能够同时读取/写入各自的位置

这些推送和弹出功能可以做到这一点,但不是线程安全的:

#包括
#包括
...
作废推送(作废*项){
sem_wait(推送可用性);
int slot=原子获取添加(尾部,1)%queue大小;
pthread_mutex_lock(访问队列[slot]);
队列[槽]=项目;
pthread_mutex_unlock(访问队列[slot]);
sem_post(pop_可用性);
}
void*pop(){
sem_wait(pop_可用性);
int slot=原子获取添加(头,1)%queue大小;
pthread_mutex_lock(访问队列[slot]);
void*item=队列[槽];
pthread_mutex_unlock(访问队列[slot]);
sem_柱(推送可用性);
}
head
tail
都初始化为0,
push\u availability
初始化为队列大小,
pop\u availability
初始化为0。只有这两个函数可以修改这些变量。(我知道head/tail可能会溢出,在数组中存储指针会使队列的线程安全性变得不重要,但这些问题对于这个问题并不重要。)

问题的一个例子是: 假设线程A和线程B调用
push
,线程C调用
pop
。线程A获取插槽0但不锁定它,然后线程B获取插槽1并向其写入数据,并发布有写入空间的消息。线程C唤醒并获取插槽0,并尝试从中读取,但线程A尚未写入该插槽


我可以通过增加head/tail和写入/读取互斥锁来解决这个问题,互斥锁阻止任何其他线程访问整个队列,但我想知道是否可以通过允许多个线程同时写入和读取队列的方式来解决这个问题。

这是我正在使用的解决方案:

作废推送(作废*项){
sem_wait(推送可用性);
int slot=原子获取添加(尾部,1)%queue大小;
while(槽满[槽]!=false);
队列[槽]=项目;
槽满[槽]=真;
sem_post(pop_可用性);
}
void*pop(){
sem_wait(pop_可用性);
int slot=原子获取添加(头,1)%queue大小;
while(槽满[槽]!=true);
void*item=队列[槽];
槽满[槽]=假;
sem_柱(推送可用性);
退货项目;
}
插槽满[i]
初始化为false)

while循环不会占用大量时间,因为信号量主要处理等待插槽打开的情况。(在测试中,while循环条件从来都不是真的。)如果复制操作很昂贵,那么使用条件变量将是一种可行的方法,但我认为平均而言,这可能比这个解决方案更昂贵


是无锁队列的有用参考,以及Mpoter的评论。

AFAIK,不安全。一个可靠、高效的多生产者-消费者队列需要一个互斥量和一个信号量或condvar(如果有界,则更多)。您应该看看无锁队列-最简单和最有名的(尽管不是性能最好的)是。