C 如何在文件描述符上创建选择块
我有一个有两个线程的进程。一个线程线程A将设置timerfd计时器,另一个线程线程B将对这些计时器执行“选择”。一旦计时器过期,线程B将向线程a指示这一点C 如何在文件描述符上创建选择块,c,linux,C,Linux,我有一个有两个线程的进程。一个线程线程A将设置timerfd计时器,另一个线程线程B将对这些计时器执行“选择”。一旦计时器过期,线程B将向线程a指示这一点 if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1) printf("Failed to open /wakeup, Errno = %d\n", errno); else { fcntl(wakeUpFd, F_SETLK, F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#create a timer and add it to a list
/* wake up timer thread */
fcntl(wakeUpFd, F_SETLK, ~F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
if(ftruncate(wakeUpFd, 2) == -1)
{
printf("Failed with ftruncate, Errno = %d\n", errno);
}
}
#create a timer and add it to a list
/* wake up timer thread */
if(write(wakeUpFd, wakeUpStr, 1) != 1)
printf("Failed to write to wakeUpFd\n");
要添加计时器,线程A将创建一个新的计时器,然后它将唤醒线程B,将该计时器包含在其对select的调用中。我正试图通过使用文件描述符来唤醒线程B。然后,线程B将调用该FD上的select以及调用timerfd返回的所有FD
问题是我无法创建一个我可以控制的FD,以便它在需要时导致select阻塞或返回
我曾尝试在调用fcntl时使用shm_open,并尝试在文件上使用open,但没有一个会导致select阻塞。我的所有尝试都会导致select立即返回。有没有办法创建一个会导致select阻塞的FD,直到我以某种方式更新该FD
尝试1-在shm_打开的情况下创建FD,并使用fcntl设置读取锁定:
从线程A创建FD
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#create a timer and add it to a list
/* wake up timer thread */
fcntl(wakeUpFd, F_SETLK, ~F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
if(ftruncate(wakeUpFd, 2) == -1)
{
printf("Failed with ftruncate, Errno = %d\n", errno);
}
}
#create a timer and add it to a list
/* wake up timer thread */
if(write(wakeUpFd, wakeUpStr, 1) != 1)
printf("Failed to write to wakeUpFd\n");
从线程A添加计时器
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#create a timer and add it to a list
/* wake up timer thread */
fcntl(wakeUpFd, F_SETLK, ~F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
if(ftruncate(wakeUpFd, 2) == -1)
{
printf("Failed with ftruncate, Errno = %d\n", errno);
}
}
#create a timer and add it to a list
/* wake up timer thread */
if(write(wakeUpFd, wakeUpStr, 1) != 1)
printf("Failed to write to wakeUpFd\n");
唤醒线程B
#when select returns
if(FD_ISSET(wakeUpFd, &timerSet))
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#check all other timer FD's
#when select returns
if(FD_ISSET(wakeUpFd, &timerSet))
{
read(wakeUpFd, wakeUpBuf, 10);
}
#check all other timer FD's
尝试2-使用shm_打开并读取/写入数据:
从线程A创建FD
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#create a timer and add it to a list
/* wake up timer thread */
fcntl(wakeUpFd, F_SETLK, ~F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
if(ftruncate(wakeUpFd, 2) == -1)
{
printf("Failed with ftruncate, Errno = %d\n", errno);
}
}
#create a timer and add it to a list
/* wake up timer thread */
if(write(wakeUpFd, wakeUpStr, 1) != 1)
printf("Failed to write to wakeUpFd\n");
从线程A添加计时器
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#create a timer and add it to a list
/* wake up timer thread */
fcntl(wakeUpFd, F_SETLK, ~F_RDLCK);
if((wakeUpFd = shm_open("/wakeup", O_RDWR|O_CREAT|O_TRUNC, 0)) == -1)
printf("Failed to open /wakeup, Errno = %d\n", errno);
else
{
if(ftruncate(wakeUpFd, 2) == -1)
{
printf("Failed with ftruncate, Errno = %d\n", errno);
}
}
#create a timer and add it to a list
/* wake up timer thread */
if(write(wakeUpFd, wakeUpStr, 1) != 1)
printf("Failed to write to wakeUpFd\n");
唤醒线程B
#when select returns
if(FD_ISSET(wakeUpFd, &timerSet))
{
fcntl(wakeUpFd, F_SETLK, F_RDLCK);
}
#check all other timer FD's
#when select returns
if(FD_ISSET(wakeUpFd, &timerSet))
{
read(wakeUpFd, wakeUpBuf, 10);
}
#check all other timer FD's
尝试3-与尝试2基本相同,但使用open而不是shm_open
Try 4-与Try 1相同,但使用fcntl(wakeUpFd、F_SETFL、~O_NONBLOCK)而不是fcntl(wakeUpFd、F_SETLK、~F_RDLCK)阅读规范,尤其是其中说明:
与常规文件相关联的文件描述符应始终为“准备读取”、“准备写入”和“错误”条件选择“真”
不能对常规文件的文件描述符设置
select()
块。您必须有一个管道、套接字或沿着这些线的东西,作为您选择的文件。使用Unix域套接字对,例如用于通信。当线程A创建一个新的timerfd时,它只需将新的描述符(一个int
)写入通信套接字commsd[0]
当线程B注意到通信套接字commsd[1]
可读时,它从中读取一个或多个int
s。每个int
显然是一个新的timerd描述符,因此线程B必须将每个描述符添加到set itselect()
s on中
在线程B中,我建议在循环中使用非阻塞读取从通信套接字读取:
char buffer[8 * sizeof(int)];
size_t head = 0, tail = 0;
ssize_t bytes;
int new_timerfd;
while (1) {
if (head >= tail)
head = tail = 0;
else
if (head > 0) {
memmove(buffer, buffer + head, tail - head);
tail -= head;
head = 0;
}
if (tail < sizeof buffer) {
bytes = recv(commsd[1], buffer + head, sizeof buffer - tail, MSG_DONTWAIT);
if (bytes > (ssize_t)0)
head += bytes;
}
if (head >= tail)
break;
while (head + sizeof (int) <= tail) {
/* Unaligned version of new_timerfd = *(int *)(buffer + head); */
memmove(&new_timerfd, buffer + head, sizeof new_timerfd);
head += sizeof (int);
/*
* Add new_timerfd to select()ed set
*/
}
}
char缓冲区[8*sizeof(int)];
头部尺寸=0,尾部尺寸=0;
ssize_t字节;
int new_timerfd;
而(1){
如果(头部>=尾部)
头=尾=0;
其他的
如果(头>0){
memmove(缓冲器、缓冲器+头部、尾部-头部);
尾-=头;
水头=0;
}
if(尾部<缓冲区大小){
bytes=recv(commsd[1],buffer+head,buffer-tail的大小,MSG_DONTWAIT);
如果(字节数>0)
头+=字节;
}
如果(头部>=尾部)
打破
while(head+sizeof(int)欢迎来到Stack Overflow。请尽快阅读。您在这里做得很好,解释了您尝试的内容,并且在询问之前明确尝试了相当数量。做得好。感谢您的回答,它非常彻底。在我的情况下,我通过内存处理通信。FD只是用来唤醒计时器处理程序。一个管道对我来说这是最快的方法。