Process Introduction
1.Process Isolation
Processes are isolated. By default, no processes can communicate with another process. Each process has their own address space.
2. Memory Layout
- Stack: The stack stores the automatic variable and function call return addresses. It is writable but not excutable. It will keep going down and get SEGFAULT if meet heap.
- Heap: When you call malloc(0) it will get the memory on heap. It will goes up and also not executable.
- Data Segment: Contains all of your globals. Start at the end of Text memory. The size is static. Also not executable.
- Text Segment: The place store our code.
Forking Introduction
Why does the example print 42 twice
#include <unistd.h> /*fork declared here*/
#include <stdio.h> /* printf declared here*/
int main() {
int answer = 84 >> 1;
printf("Answer: %d", answer);
fork();
return 0;
}
When calling fork(), the whole memory including buffer will all be copyed.
Difference between parent and child
If fork() return -1, somethings goes wrong. If 0, we are currently inside child process. If 1, we are currently in the parent process. We can use getpid() to get own pid, gitppid() to get parent pid. They are using the same kernel file descriptor. If one process rewinds the random access back to be beginning of file, both process will be affected.
Wait for child
pid_t pid = fork()
if(pid = -1){
perror("fork wrong");
exit(1);
}
if(pid > 0){
waitpid(pid, &status, 0);
}else{
exit(0);
}
exec family
We can use exec after forking. It will replace everything after exec(). So everything need to be done in child process should before exec().
What does child inherit from the parent
- open file handles. If the parent later seeks, say or back to beginning will affect both process. We can call close to disconnect.
- signal handlers
- current working directory
- environment variables
Zombie
After finished, the child process still hold a slot in kernel process table and some informations. They are only available if the child process is waited. For the short process, it doesn't matter. However, if too many zombies. There will be not enough empty slot for new processes.
waitpid(child, &status, 0);//will clean up and wait for child to finish
Environment variables
Environment variables are variables that all processes use.
char* home = getenv("HOME");
setenv("HOME","home/bhuvan",1)
Each process get its own dictionary. If parent change their environment variable, it won't transfer to their child.
Process Control
Find out the exit value of my child
int status;
pid_t child_pid = fork();
if(child == -1) return 1;
if(child > 0){
pid_t pid = waitpid(child_pid,&status,0);
if(pid != -1 && WIFEXITED(status)){
int lowest8 = WEXITSTATUS(status); // A process can only have 256 return values
printf("Process %d return %d", pid, lowest8);
}
}else{
execl("/bin/ls","bin/ls",".",(char*)NULL); "ls ."
}
Thread
How thread's stack work
- Main function will has automatic variables, stored on stack. There is a simple pointer to keep tracking how large is the stack. If the thread call another function, the ponter will go down. And the old stack pointer value will be stored. When the function return, it can be back the old pointer very fast.
- In a multi-thread process, there will be multiple stack and only one address sapce. We can create many threads. They all live inside the same virtual memory and all can see the heap, global variables and program code.
Example:
int love(char* str){
printf("%s\n",str);
return 1;
}
main(){
pthread_t id;
void* result;
pthread_create(&id, NULL, love, "Wo Ai SYH.");
pthread_join(id, &status);
return;
}
Difference between process and thread
- Process is isolation and thread share the same global memory
- Process is more security
- Create thread is much faster. But one thread can terminate the whole process
Pthread_join() and Pthread_exit()
Pthread_join() and Pthread_exit() will all give the other threads enough time to finish their work. However, pthread_exit will not wait for the return.
int main(){
pthread_t id1;
pthread_t id2;
pthread_create(&id1, NULL, myfun, "CNM");
pthread_create(&id2, NULL, myfun, "TMD");
pthread_exit(NULL);
}
int main(){
pthread_t id1;
pthread_t id2;
int result;
pthread_create(&id1, NULL, myfun, "CNM");
pthread_create(&id2, NULL, myfun, "TMD");
pthread_join(id1, &result);
pthread_join(id2, &result);
}
pthread_join() can:
- Wait for thread to finish
- Clean up
- Grap the return value
How to terminated a thread
- Returning from thread
- Pthread_exit
- Pthread_cancel
- Terminating the process(exit(0),return)
Pass pointers to stack variables from one thread to another
We need to focus on the life time of stack variable. Use static or pthread_join().
int start = 42;
int result;
pthread_t tid;
pthread_create(&tid, NULL, fun, &start);
pthread_join(tid, &result);
We can fork a process with multiple thread, but the child process will only have one thread.
strtok, strerror, getenv, asctime are not thread safe
Exam Prep
1.What resources are shared between threads in the same process?
The heap, global variable and other segment except stack.
2.Explain the operating system actions required to perform a process context switch
3.Explain the actions required to perform a thread context switch to a thread in the same process
We can use pthread_create to send stack variable to another thread in the same process. But we need to use pthread_join to keep the stack variable valid.
4. How can a process be orphaned? What does the process do about it?
If the parent process terminated when the child process still running. The init process will become its new parent and init process will wait for every process.
5. How do you create a process zombie?
If the parent don't wait for their child. There will be slot and information of that zombie holded in process table. If we are running a long-run process, there might be not enough space for new process. The thread terminated and doesn't waited is zombie process.
6. Under what conditions will a multi-threaded process exit? (List at least 4)
- Pthread_exit
- Termination of main thread
- pthread_cancel
- Return from thread