linux 中的信号处理和中断的函数调用?
signal handling in linux and interrupted function calls?
我需要解决描述为
的问题
有两个进程 p1、p2 和两个变量 x、y 进程 p1 和 p2 应该更新 x 和 y 的值,因为 p1 将更新 y = x + 1,而 p2 将更新 x = y + 1 并保持一致。 IE。当 p1 同时读取 x 时,p2 无法写入 x 的更新值,当 p1 同时写入 y 时,p2 无法读取 y 的值。
通过查看问题,我们可以观察到存在死锁。 (read-x by p1)-->(read-y by p1) -->(update-y by p1)-->(read-y by p2)-->(read-x by p2) --> (update-x by p2 )
为了解决死锁,我编写了一个使用信号和共享内存的程序。
在主函数中,信号处理程序使用 SIGUSR1 and SIGUSR2
信号编号注册,信号编号由信号处理程序 func1() 和 func2() 处理。生成的信号也使 x 和 y 的值同步。每当进程 p1 完成它的工作时,它就会为进程 p2 生成一个信号,该信号使用 Kill(pid,signo) and vice versa
进行传输,它们在无限循环中工作并休眠一段时间。
它打印出正确(一致)的输出,但此实现存在问题,因为
最初打印输出需要几秒钟,然后一次打印大量序列(行束)。
应在此代码中进行哪些修改,以便它在几乎恒定的时间后打印输出?
有人可能会建议使用等量的睡眠时间,但没有用。
void func1(int signo){
*shm2 = *shm1 +1;
cout<<"Value of Y is\t"<<*shm2<<"\n";
signal(signo,func1);
}
void func2(int signo){
*shm1 = *shm2 + 1;
cout<<"Value of X is\t"<<*shm1<<"\n";
signal(signo,func2);
}
int main(){
int pid=0,ppid=0;
int shmid1,shmid2;
signal(SIGUSR1,func1);
signal(SIGUSR2,func2);
shmid1 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);
shmid2 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);
if(shmid1 < 0 || shmid2 < 0 ){
cout<<"Something goes wrong during creation\n";
exit(1);
}
// Attach shared memory to an address
shm1 = (int *) shmat(shmid1 , (void*)0 , 0);
shm2 = (int *) shmat(shmid2 , (void*)0 , 0);
if( *shm1 == -1 || *shm2 == -1){
cout<<"Memory can't be attached\n";
exit(1);
}
pid = fork();
if(pid < 0 ){
cout<<"fork() error\n";
exit(1);
}
ppid =getppid();
if(pid > 0){
while(1){
sleep(500);
kill(pid,SIGUSR1);
}
}
else{
while(1){
sleep(5);
kill(ppid,SIGUSR2);
}
}
return 0;
}
这不是死锁。死锁是指 P1 等待 P2 完成而 P2 等待 P1 完成的情况...
你的问题最终是并发访问的问题,解决方案是使用锁。锁让 program/thread 以原子方式完成某些任务。策略是使用两个process/threads共享的锁L
,这样:GET(L); do some task; RELEASE(L);
您的代码中的错误是信号传递中断了您的 sleep
呼叫。当这样的调用被中断时,它不会在处理结束时重新启动。手册说:
If the sleep() function returns due to the delivery of a signal,
the value returned will be the unslept amount (the requested time
minus the time actually slept) in seconds.
因此您可以像这样修改循环:
if (pid > 0) {
while(1) {
int v = 500;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(pid,SIGUSR1);
}
}
else {
while(1) {
int v=5;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(ppid,SIGUSR2);
}
}
我还可以建议不要使用旧的 signal
接口,而是使用 sigaction
更安全可靠(您永远不必在信号处理程序中重置 signal
处理例如)。
我需要解决描述为
的问题有两个进程 p1、p2 和两个变量 x、y 进程 p1 和 p2 应该更新 x 和 y 的值,因为 p1 将更新 y = x + 1,而 p2 将更新 x = y + 1 并保持一致。 IE。当 p1 同时读取 x 时,p2 无法写入 x 的更新值,当 p1 同时写入 y 时,p2 无法读取 y 的值。
通过查看问题,我们可以观察到存在死锁。 (read-x by p1)-->(read-y by p1) -->(update-y by p1)-->(read-y by p2)-->(read-x by p2) --> (update-x by p2 )
为了解决死锁,我编写了一个使用信号和共享内存的程序。
在主函数中,信号处理程序使用 SIGUSR1 and SIGUSR2
信号编号注册,信号编号由信号处理程序 func1() 和 func2() 处理。生成的信号也使 x 和 y 的值同步。每当进程 p1 完成它的工作时,它就会为进程 p2 生成一个信号,该信号使用 Kill(pid,signo) and vice versa
进行传输,它们在无限循环中工作并休眠一段时间。
它打印出正确(一致)的输出,但此实现存在问题,因为 最初打印输出需要几秒钟,然后一次打印大量序列(行束)。
应在此代码中进行哪些修改,以便它在几乎恒定的时间后打印输出?
有人可能会建议使用等量的睡眠时间,但没有用。
void func1(int signo){
*shm2 = *shm1 +1;
cout<<"Value of Y is\t"<<*shm2<<"\n";
signal(signo,func1);
}
void func2(int signo){
*shm1 = *shm2 + 1;
cout<<"Value of X is\t"<<*shm1<<"\n";
signal(signo,func2);
}
int main(){
int pid=0,ppid=0;
int shmid1,shmid2;
signal(SIGUSR1,func1);
signal(SIGUSR2,func2);
shmid1 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);
shmid2 = shmget(IPC_PRIVATE , sizeof(int) , 0666|IPC_CREAT);
if(shmid1 < 0 || shmid2 < 0 ){
cout<<"Something goes wrong during creation\n";
exit(1);
}
// Attach shared memory to an address
shm1 = (int *) shmat(shmid1 , (void*)0 , 0);
shm2 = (int *) shmat(shmid2 , (void*)0 , 0);
if( *shm1 == -1 || *shm2 == -1){
cout<<"Memory can't be attached\n";
exit(1);
}
pid = fork();
if(pid < 0 ){
cout<<"fork() error\n";
exit(1);
}
ppid =getppid();
if(pid > 0){
while(1){
sleep(500);
kill(pid,SIGUSR1);
}
}
else{
while(1){
sleep(5);
kill(ppid,SIGUSR2);
}
}
return 0;
}
这不是死锁。死锁是指 P1 等待 P2 完成而 P2 等待 P1 完成的情况...
你的问题最终是并发访问的问题,解决方案是使用锁。锁让 program/thread 以原子方式完成某些任务。策略是使用两个process/threads共享的锁L
,这样:GET(L); do some task; RELEASE(L);
您的代码中的错误是信号传递中断了您的 sleep
呼叫。当这样的调用被中断时,它不会在处理结束时重新启动。手册说:
If the sleep() function returns due to the delivery of a signal, the value returned will be the unslept amount (the requested time minus the time actually slept) in seconds.
因此您可以像这样修改循环:
if (pid > 0) {
while(1) {
int v = 500;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(pid,SIGUSR1);
}
}
else {
while(1) {
int v=5;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(ppid,SIGUSR2);
}
}
我还可以建议不要使用旧的 signal
接口,而是使用 sigaction
更安全可靠(您永远不必在信号处理程序中重置 signal
处理例如)。