提问人:Edison von Myosotis 提问时间:11/6/2023 最后编辑:Edison von Myosotis 更新时间:11/8/2023 访问量:88
SysV 信号量线程线程弹跳
SysV semaphore thread thread bouncing
问:
我有一个类似于 Java 和 .NET 中的监视器的监视器类。它可以比互斥锁和条件变量的简单组合更有效。因此,我有一个信号量,它允许输入先前锁定的关键部分,以及一个信号量,用于通知正在等待慢速竞争路径的线程。如果线程正在等待,则在两个信号量上都在等待。
在 Win32 中,两个信号量是分开的,在 Linux 上,我使用设置为允许 sth 的 SysV 信号量。就像 Win32 上的 WaitForMultipleObjects() 一样,等待监视器的“互斥锁”部分被解锁,以及通知部分被单独解锁。
在上面的代码中,我通过两个信号量集来模拟这一点(不使用 semctl() 进行初始化,因为这对 Linux 来说不是必需的)。线程 ist 生成两次,每个线程首先等待两个信号量发出信号,并向相反线程的信号量集的两个信号量发出信号。等待部分类似于我的监视器类,但 singalling 部分同时向集合的两个信号量发出信号,而我在执行 notify() 和离开“互斥锁”保护部分时分别向它们发出信号;因此,对第一组进行单独初始化以检查这是否有效。
但不幸的是,这两个线程都停在第一个 semop 并永远沉睡。你能告诉我我犯了什么错误吗?代码是 C++20,以使其尽可能简短。
#include <thread>
#include <initializer_list>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/stat.h>
using namespace std;
int main()
{
int
setA = semget( IPC_PRIVATE, 2, S_IRUSR | S_IWUSR ),
setB = semget( IPC_PRIVATE, 2, S_IRUSR | S_IWUSR );
if( setA == -1 || setB == -1 )
return EXIT_FAILURE;
static auto xSemop = []( int set, std::initializer_list<sembuf> sems )
{
int ret;
while( (ret = ::semop( set, const_cast<sembuf *>(sems.begin()), sems.size() )) == EINTR );
return ret;
};
if( xSemop( setA, { { 0, 1, 0 } } ) || xSemop( setA, { { 1, 1, 0 } } ) )
return EXIT_FAILURE;
constexpr size_t ROUNDS = 1'000'000;
auto thr = []( int mySet, int yourSet )
{
for( size_t r = ROUNDS; r--; )
if( xSemop( mySet, { { 0, -1, 0 }, { 1, -1, 0 } } )
|| xSemop( yourSet, { { 0, 1, 0 }, { 1, 1, 0 } } ) )
terminate();
};
jthread
thrA( thr, setA, setB ),
thrB( thr, setB, setA );
}
答:
0赞
Edison von Myosotis
11/8/2023
#1
我明白了:如果我增加信号量的计数器,我必须在 sembuf::sem_flg 上设置IPC_NOWAIT,否则我认为线程会等到另一个服务员在集合中减少这个 sempahore。我不知道这应该有什么好处,但我可以忍受。
评论
semop()
xSemop
semop(1, (struct sembuf[]){ { 0, 1, 0 } }, 1)