不断地读写管道以一种方式工作,而另一种方式只工作一次
Constantly reading and writing pipe works one way and just once in the other
我正在 Raspberry Pi 4 上用 C++ 编写程序来控制一些电机并通过 GPIO 引脚取回速度传感器的信息。
为此,有一个带有“fork”的主控制程序。
父进程进行所有计算,子进程通过 SPI 通信不断发送和接收数据(发送和接收数据是同时完成的,库不允许做任何一个)。
在每个循环中,子级读取父级发送的数据(这部分有效)并将输入读取的数据(工作一次)发送回父级。
我实际上已经用电缆连接了“读取”数据,因此我可以控制输入并确定它们的状态。
在下面的示例中,我将请求的信息提供给程序,让父级写入子级,这有效(选择电机 0/15,速度为 0,方向 0=停止和不停止程序)
第一次尝试时,它告诉我读取的数据是 10,这是正确的。
然后我将我的跳线移动到另一个值(在本例中为 15),但第二次尝试时它仍然给我 10
我检查了我的程序,子进程的write收到了好的数据,确实是管道有问题,我想不通。管道似乎关闭了...
这是终端视图
问题出在父线之间
if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }
和子线
//If here I print the content of "In0", it is correct and fitting what the program read
if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
这里是为了便于阅读而删除了大部分内容的程序。
#include <bcm2835.h> //SPI & GPIO communication library
#include <stdio.h>
#include <unistd.h> //got fork() in it
#include <sys/wait.h>
#include <vector>
#include <iostream> //for Cout to display stuff
#include <thread> //for multithreading
#include <string.h>
#include <time.h>
using std::vector;
int SRDInit();
char* SendReceiveData(char* SpiOut, char* SpiIn); //Defines the existance of this function and will check in the compiled stuff if it exists (spoiler : it does)
int SRDClose();
int main(int MotNb, int Spd1, int Dir1)
{
//Fork and multiprocessing stuff
bool EndThis = false; //Variable for ending the continous look of sending and receiving data from shift registers
//SPI Communication buffers and data storages
char SpiOut[2]={0,0}; //Defining the char to send by SPI and set it to 0
short int In0[2] = {0}; //Char array for receiving data
int Sp1 = 0; // iteration variable for speed
short int SpdDir[4] = {0, 0, 0, 0}; //creates a table with 4 ints inside 0 for motor number, 1 for Speed, 2 for Dirrection and 3 for killing the child
//###################################################################################
//Actual beginning of the program
//###################################################################################
int fdPC[2]; //File descriptor for the piping Parent to child
int fdCP[2]; //File descriptor for the piping Child to Parent
std::cout << "Init FD" << '\n';
if (pipe(fdPC) == -1){ //creating the pipe for communication with the second program sending and receiving data
//fd[0] = Read fd[1]=write
std::cout << "an error occured while creating the pipe Parent to Child" << std::endl;
return 1;
}
if (pipe(fdCP) == -1){ //creating the pipe for communication with the second program sending and receiving data
//fd[0] = Read fd[1]=write
std::cout << "an error occured while creating the pipe Child to Parent" << std::endl;
return 1;
}
std::cout << "Forking" << '\n';
int id = fork(); //forking the program to create a second one playing on another processor
std::cout << "Forked ID = " << id << '\n';
if (id < 0){
std::cout << "An error occured while forking :'(" << std::endl;
}
else if (id > 0){ //if in the main process
std::cout << "Enter Main process" << '\n';
//###################################################################################
//Main process.
//###################################################################################
close (fdPC[0]); //closing the read side of the Parent to child pipe
close (fdCP[1]); //closing the write side of the child to parent pipe
fcntl(fdPC[1], F_SETFL,O_NONBLOCK);
fcntl(fdCP[0], F_SETFL,O_NONBLOCK);
int MotNb = 0; //variable for the number of the motor to be modified
short int OldIn0[2] = {0, 0};
short int NewIn0[2] = {0, 0};
while(EndThis == false){
std::cout << "Gi'me Motor 0-15" <<'\n';
std::cin >> MotNb;
std::cout << "Gi'me speed" <<'\n';
std::cin >> Spd1;
std::cout << "Gi'me dirrection 0=3= stop 1=fwd 2=bwd" <<'\n';
std::cin >> Dir1;
std::cout << "Stop that? Y/N" <<'\n'; //check if we want to close the program
std::cin >> EndProg;
SpdDir[0] = MotNb; //storing the Motor number
SpdDir[1] = Spd1; //storing the speed
SpdDir[2] = Dir1; // storing the dirrection
if(write(fdPC[1], SpdDir, sizeof(short int)*4) == -1) { std::cout << "Something went wrong in Parent write :'( " <<'\n'; } //Writing through the pipe to send data to the Child
if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }
NewIn0[0] = In0[0];
NewIn0[1] = In0[1];
if (NewIn0[0] != OldIn0[0] || NewIn0[1] != OldIn0[1]) {
std::cout << "SOMETHING CHANGED !!! Old In0 = " << +OldIn0[0]<< +OldIn0[1] << " and NewIn0 = " << +NewIn0[0]<< +NewIn0[1] << '\n';
OldIn0[0] = NewIn0[0];
OldIn0[1] = NewIn0[1];
}
if (SpdDir[3] > 0){
EndThis = true;
std::cout << "Stopping main" <<'\n'; //check if we want to close the program
}
} //End of PARENT while
write(fdPC[1], SpdDir, sizeof(int)*3); //Writing through the pipe to send data to the Child for ending the program
//End of main program, closing everything and freeing memory because we're tidy people
close (fdPC[1]); //closing the write side of the Parent to child pipe
close (fdCP[0]); //closing the read side of the child to parent pipe
if (wait(NULL) == -1){ //wait for the child to finish working == -1
std::cout << "No children to wait for" << std::endl;
}else {
std::cout << "waiting for children to finish" << '\n';
}
}
else{ // if in the secondary process
std::cout << "Enter child process" << '\n';
//###################################################################################
//Child process. Send Speed and dirrection requested and receive data (because no choice for receiving)
//###################################################################################
close (fdPC[1]); //closing the write side of the Parent to child pipe
close (fdCP[0]); //closing the read side of the child to parent pipe
fcntl(fdPC[0], F_SETFL,O_NONBLOCK);
fcntl(fdCP[1], F_SETFL,O_NONBLOCK);
int MotNb = 0; //variable for the number of the motor to be modified
//Actual beginning of child program
char* SpiIn=(char*)malloc(sizeof(char)*17); //creation de la data qui sera échangée malloc est fermé apres l'appel a la fonction
if(SpiIn==NULL){
perror("Char allocation of SendReceiveData FAILED !!");
return 1;
}
while(EndThis == false){
read(fdPC[0], SpdDir, sizeof(short int)*4);//read data from the pipe put them in SpdDir varaible
MotNb = SpdDir[0]; //storing the motor nb
Spd1 = SpdDir[1]; //storing the speed
Dir1 = SpdDir[2]; // storing the dirrection
//Some amazing coding has been deleted here ;)
In0Raw = SendReceiveData(SpiOut, SpiIn); //Send data in "SpiOut" and puts the data received in In0Raw
In0[0] = In0Raw[1]; //Data is no read in the logical direction TBC
In0[1] = In0Raw[0]; //Data is no read in the logical direction TBC
//If here I print the content of "In0", it is correct and fitting what the program read
if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
sleep(1);
if (SpdDir[3] > 0){
EndThis = true;
std::cout << "Ending child" << '\n';
}
} //End of CHILD while
//End of child program, closing everything and freeing memory because we're tidy people
close (fdPC[0]); //closing the read side of the Parent to child pipe
close (fdCP[1]); //closing the write side of the child to parent pipe
free(In0Raw); //free memory allocated to In0Raw for "SendReceiveData"
std::cout << "Child ended" << '\n';
exit(EXIT_SUCCESS);
}
//###################################################################################
if (id > 0){
std::cout << "End of program enter a key and press ENTER to finish" <<'\n';
std::cin >> Spd1;
SRDClose();
free(In0Raw); //release memory of the pointer just in case
}
return 0;
}
如果您想知道“SendReceiveData”是什么,它只是一个通过 SPI 连接发送和接收数据的非常小的函数。它运行良好,非常基础 ;)
我知道问题出在哪里,但我完全不知道问题出在哪里。看起来管道在从 Child 写到 Parent 后关闭了,但它在另一个方向上工作得很好,从 Parent 发送指令到 Child
(如果需要,我可以复制整个代码而不是这个摘录)
预先感谢您的帮助! :)
我已经阅读了文档(由朋友提供)write() manual,它没有帮助,但对某些人可能有用。
我尝试使用 errno
来理解错误,为此我检查了文档 errno manual 并且很有用。
write() 发回了与“EAGAIN”相对应的错误“资源暂时不可用”,但最重要的是,它说“可能与 EWOULDBLOCK 的值相同”
对应于“操作会阻塞”
我搜索并找到了一个答案是“缓冲区已满”的讨论
所以,我问是否可以覆盖 write() 文件描述符中的数据,答案是“不”:'(
Is it possible to overwrite a write() data?
您必须在再次写入之前读取文件描述符中的数据。
显然,线程更好,我必须调查一下。
希望这对某人有所帮助。
我正在 Raspberry Pi 4 上用 C++ 编写程序来控制一些电机并通过 GPIO 引脚取回速度传感器的信息。
为此,有一个带有“fork”的主控制程序。 父进程进行所有计算,子进程通过 SPI 通信不断发送和接收数据(发送和接收数据是同时完成的,库不允许做任何一个)。
在每个循环中,子级读取父级发送的数据(这部分有效)并将输入读取的数据(工作一次)发送回父级。
我实际上已经用电缆连接了“读取”数据,因此我可以控制输入并确定它们的状态。
在下面的示例中,我将请求的信息提供给程序,让父级写入子级,这有效(选择电机 0/15,速度为 0,方向 0=停止和不停止程序)
第一次尝试时,它告诉我读取的数据是 10,这是正确的。
然后我将我的跳线移动到另一个值(在本例中为 15),但第二次尝试时它仍然给我 10
我检查了我的程序,子进程的write收到了好的数据,确实是管道有问题,我想不通。管道似乎关闭了...
这是终端视图
问题出在父线之间
if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }
和子线
//If here I print the content of "In0", it is correct and fitting what the program read
if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
这里是为了便于阅读而删除了大部分内容的程序。
#include <bcm2835.h> //SPI & GPIO communication library
#include <stdio.h>
#include <unistd.h> //got fork() in it
#include <sys/wait.h>
#include <vector>
#include <iostream> //for Cout to display stuff
#include <thread> //for multithreading
#include <string.h>
#include <time.h>
using std::vector;
int SRDInit();
char* SendReceiveData(char* SpiOut, char* SpiIn); //Defines the existance of this function and will check in the compiled stuff if it exists (spoiler : it does)
int SRDClose();
int main(int MotNb, int Spd1, int Dir1)
{
//Fork and multiprocessing stuff
bool EndThis = false; //Variable for ending the continous look of sending and receiving data from shift registers
//SPI Communication buffers and data storages
char SpiOut[2]={0,0}; //Defining the char to send by SPI and set it to 0
short int In0[2] = {0}; //Char array for receiving data
int Sp1 = 0; // iteration variable for speed
short int SpdDir[4] = {0, 0, 0, 0}; //creates a table with 4 ints inside 0 for motor number, 1 for Speed, 2 for Dirrection and 3 for killing the child
//###################################################################################
//Actual beginning of the program
//###################################################################################
int fdPC[2]; //File descriptor for the piping Parent to child
int fdCP[2]; //File descriptor for the piping Child to Parent
std::cout << "Init FD" << '\n';
if (pipe(fdPC) == -1){ //creating the pipe for communication with the second program sending and receiving data
//fd[0] = Read fd[1]=write
std::cout << "an error occured while creating the pipe Parent to Child" << std::endl;
return 1;
}
if (pipe(fdCP) == -1){ //creating the pipe for communication with the second program sending and receiving data
//fd[0] = Read fd[1]=write
std::cout << "an error occured while creating the pipe Child to Parent" << std::endl;
return 1;
}
std::cout << "Forking" << '\n';
int id = fork(); //forking the program to create a second one playing on another processor
std::cout << "Forked ID = " << id << '\n';
if (id < 0){
std::cout << "An error occured while forking :'(" << std::endl;
}
else if (id > 0){ //if in the main process
std::cout << "Enter Main process" << '\n';
//###################################################################################
//Main process.
//###################################################################################
close (fdPC[0]); //closing the read side of the Parent to child pipe
close (fdCP[1]); //closing the write side of the child to parent pipe
fcntl(fdPC[1], F_SETFL,O_NONBLOCK);
fcntl(fdCP[0], F_SETFL,O_NONBLOCK);
int MotNb = 0; //variable for the number of the motor to be modified
short int OldIn0[2] = {0, 0};
short int NewIn0[2] = {0, 0};
while(EndThis == false){
std::cout << "Gi'me Motor 0-15" <<'\n';
std::cin >> MotNb;
std::cout << "Gi'me speed" <<'\n';
std::cin >> Spd1;
std::cout << "Gi'me dirrection 0=3= stop 1=fwd 2=bwd" <<'\n';
std::cin >> Dir1;
std::cout << "Stop that? Y/N" <<'\n'; //check if we want to close the program
std::cin >> EndProg;
SpdDir[0] = MotNb; //storing the Motor number
SpdDir[1] = Spd1; //storing the speed
SpdDir[2] = Dir1; // storing the dirrection
if(write(fdPC[1], SpdDir, sizeof(short int)*4) == -1) { std::cout << "Something went wrong in Parent write :'( " <<'\n'; } //Writing through the pipe to send data to the Child
if (read(fdCP[0], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in Parent read :'( " <<'\n'; }
NewIn0[0] = In0[0];
NewIn0[1] = In0[1];
if (NewIn0[0] != OldIn0[0] || NewIn0[1] != OldIn0[1]) {
std::cout << "SOMETHING CHANGED !!! Old In0 = " << +OldIn0[0]<< +OldIn0[1] << " and NewIn0 = " << +NewIn0[0]<< +NewIn0[1] << '\n';
OldIn0[0] = NewIn0[0];
OldIn0[1] = NewIn0[1];
}
if (SpdDir[3] > 0){
EndThis = true;
std::cout << "Stopping main" <<'\n'; //check if we want to close the program
}
} //End of PARENT while
write(fdPC[1], SpdDir, sizeof(int)*3); //Writing through the pipe to send data to the Child for ending the program
//End of main program, closing everything and freeing memory because we're tidy people
close (fdPC[1]); //closing the write side of the Parent to child pipe
close (fdCP[0]); //closing the read side of the child to parent pipe
if (wait(NULL) == -1){ //wait for the child to finish working == -1
std::cout << "No children to wait for" << std::endl;
}else {
std::cout << "waiting for children to finish" << '\n';
}
}
else{ // if in the secondary process
std::cout << "Enter child process" << '\n';
//###################################################################################
//Child process. Send Speed and dirrection requested and receive data (because no choice for receiving)
//###################################################################################
close (fdPC[1]); //closing the write side of the Parent to child pipe
close (fdCP[0]); //closing the read side of the child to parent pipe
fcntl(fdPC[0], F_SETFL,O_NONBLOCK);
fcntl(fdCP[1], F_SETFL,O_NONBLOCK);
int MotNb = 0; //variable for the number of the motor to be modified
//Actual beginning of child program
char* SpiIn=(char*)malloc(sizeof(char)*17); //creation de la data qui sera échangée malloc est fermé apres l'appel a la fonction
if(SpiIn==NULL){
perror("Char allocation of SendReceiveData FAILED !!");
return 1;
}
while(EndThis == false){
read(fdPC[0], SpdDir, sizeof(short int)*4);//read data from the pipe put them in SpdDir varaible
MotNb = SpdDir[0]; //storing the motor nb
Spd1 = SpdDir[1]; //storing the speed
Dir1 = SpdDir[2]; // storing the dirrection
//Some amazing coding has been deleted here ;)
In0Raw = SendReceiveData(SpiOut, SpiIn); //Send data in "SpiOut" and puts the data received in In0Raw
In0[0] = In0Raw[1]; //Data is no read in the logical direction TBC
In0[1] = In0Raw[0]; //Data is no read in the logical direction TBC
//If here I print the content of "In0", it is correct and fitting what the program read
if(write(fdCP[1], In0, sizeof(short int)*2) == -1) { std::cout << "Something went wrong in child write :'( " <<'\n'; }; //sending data through the pipe
sleep(1);
if (SpdDir[3] > 0){
EndThis = true;
std::cout << "Ending child" << '\n';
}
} //End of CHILD while
//End of child program, closing everything and freeing memory because we're tidy people
close (fdPC[0]); //closing the read side of the Parent to child pipe
close (fdCP[1]); //closing the write side of the child to parent pipe
free(In0Raw); //free memory allocated to In0Raw for "SendReceiveData"
std::cout << "Child ended" << '\n';
exit(EXIT_SUCCESS);
}
//###################################################################################
if (id > 0){
std::cout << "End of program enter a key and press ENTER to finish" <<'\n';
std::cin >> Spd1;
SRDClose();
free(In0Raw); //release memory of the pointer just in case
}
return 0;
}
如果您想知道“SendReceiveData”是什么,它只是一个通过 SPI 连接发送和接收数据的非常小的函数。它运行良好,非常基础 ;)
我知道问题出在哪里,但我完全不知道问题出在哪里。看起来管道在从 Child 写到 Parent 后关闭了,但它在另一个方向上工作得很好,从 Parent 发送指令到 Child
(如果需要,我可以复制整个代码而不是这个摘录)
预先感谢您的帮助! :)
我已经阅读了文档(由朋友提供)write() manual,它没有帮助,但对某些人可能有用。
我尝试使用 errno
来理解错误,为此我检查了文档 errno manual 并且很有用。
write() 发回了与“EAGAIN”相对应的错误“资源暂时不可用”,但最重要的是,它说“可能与 EWOULDBLOCK 的值相同” 对应于“操作会阻塞”
我搜索并找到了一个答案是“缓冲区已满”的讨论
所以,我问是否可以覆盖 write() 文件描述符中的数据,答案是“不”:'( Is it possible to overwrite a write() data?
您必须在再次写入之前读取文件描述符中的数据。
显然,线程更好,我必须调查一下。
希望这对某人有所帮助。