Optimizing SIGCHLD Handler for Prime Number Generation

  • Thread starter Thread starter TylerH
  • Start date Start date
Click For Summary
SUMMARY

The discussion focuses on optimizing the SIGCHLD handler in a program designed for generating a complete, ordered list of prime numbers using worker processes. The original implementation faced issues with hanging output due to improper handling of child process termination. The solution involved moving the wait logic into the main function where results are required, thus resolving the issue. Additionally, the user seeks to optimize memory usage by minimizing Copy-On-Write (COW) page duplication when processes access shared data.

PREREQUISITES
  • Understanding of signal handling in C++ using sigaction
  • Familiarity with process management functions such as wait() and WIFEXITED()
  • Knowledge of memory management concepts, particularly Copy-On-Write (COW) behavior
  • Experience with the mpz_class type from the GMP library for handling large integers
NEXT STEPS
  • Research techniques for analyzing Copy-On-Write (COW) page usage in Linux
  • Explore shared memory mechanisms in C++ to reduce memory duplication
  • Learn about optimizing signal handlers for performance in multi-process applications
  • Investigate the use of debuggers like GDB to trace process behavior and memory usage
USEFUL FOR

Software developers, particularly those working with C++ and process management, as well as anyone interested in optimizing memory usage in concurrent applications.

TylerH
Messages
729
Reaction score
0
My program is generating a complete, ordered list of primes and children are the worker processes deciding the primality of a single number and exiting with true iff the number they are assigned it prime. The map procs maps pids to numbers being checked.

Here is where I register the handler:
Code:
	struct sigaction sa;
	sa.sa_handler = sigchld_handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_NOCLDSTOP;
	if (sigaction(SIGCHLD, &sa, NULL) < 0) {
		perror("sigaction");
		exit(1);
	}

Here is my handler:
Code:
void sigchld_handler(int signal){
	int status;
	pid_t pid;
	
	cout << "Entered handler." << endl;
	while((pid = wait(&status)) > 0){
		cout << "Entered loop." << endl;
		if(!WIFEXITED(status)){
			cerr << "Error: " << pid << " exited abnormally." << endl;
			exit(1);
		}
		auto n = procs.find(pid)->second;
		procs.erase(pid);
		cout << "1" << endl;
		if(status){
			cout << "Tested true: " << n << endl;
			buffer.insert(n);
		}
		else
			cout << "Tested false: " << n << endl;
		cout << "2" << endl;
		bool min = true;
		while(min && !buffer.empty()){
			mpz_class n = *buffer.begin();
			for(auto i = procs.begin();(min = mpz_class(i->second) > n) && i != procs.end();i++);
			if(min){
				primes.push_back(n);
				cout << "Added: " << n << endl;
				buffer.erase(n);
			} else
				cout << "Buffered: " << n << endl;
		}
	}
	/*if(pid != ECHILD){
		cerr << "Error: wait() returned negative other than ECHILD" << endl;
		exit(1);
	}*/
}

When the program is ran, the only output I get is:
Entered handler.
Entered loop.
1
[hang, as in, nothing is printed and it doesn't exit]

ps -a on another terminal prints:
10304 pts/0 00:00:00 a.out
10306 pts/0 00:00:00 a.out <defunct>
10307 pts/0 00:00:00 a.out <defunct>
10308 pts/0 00:00:00 a.out <defunct>
10310 pts/1 00:00:00 ps

I'd be glad to post the rest of the code for anyone who thinks it could be the culprit, I just didn't want to bombard you with code that probably (I assume) isn't helpful.
 
Technology news on Phys.org
Are you using a debugger? Since you're seeing "Entered handler" and "Entered loop", but not seeing "1", or "Error <pid> exited abnormally", it would seem that something untoward is happening in this code:
Code:
auto n = procs.find(pid)->second;
procs.erase(pid);
 
I still don't really know what was going wrong, but I suppose it probably had to do with my false assumption that signals are queued.

I fixed it by doing the waiting in the function in which the results of the child processes are needed. It works now, so I'd like to start optimizing it. Is there any way to analyze how many/which COW pages are being copied? Are COW pages copied when the parent writes or only when the child does it? If they're copied when the parent writes to them, it there any way to disable this or get a chuck of memory which doesn't do this? For context, I only want 1 copy of the list of all primes, to keep memory waste to a minimum. I know children will never write to the list, because they are guaranteed to have all the primes they need to complete their check. (From 2 to sqrt(n), where n is the number being checked.)
 

Similar threads

  • · Replies 36 ·
2
Replies
36
Views
2K
  • · Replies 4 ·
Replies
4
Views
5K
  • · Replies 8 ·
Replies
8
Views
5K
Replies
6
Views
2K
  • · Replies 8 ·
Replies
8
Views
9K
  • · Replies 11 ·
Replies
11
Views
3K
  • · Replies 4 ·
Replies
4
Views
3K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 4 ·
Replies
4
Views
4K
  • · Replies 7 ·
Replies
7
Views
4K