An instance of execution within the same program in a shared memory address space
Traditionally, upon fork() all resources owned by the parent are duplicated and the copy is given to child. It is ineffi cient in that it copies much data that might otherwise be shared. Worse still, if the new process were to immediately execute a new image, all that copying will be wasted.
In Linux, fork() is implemented through the use of copy-on-write (COW) pages. COW is a technique to delay or altogether prevent the copying of the data. Rather than duplicate the process address space, the parent and child can share a single copy.
The data is marked in such a way that if it is written to, a duplicate is made and each process receives a unique copy. In the case that the pages are never written, for example, if exec() is called immediately after fork(), they never need be copied.
Linux implements fork() via the clone() system call. This call takes a series of flags that specify which resources, if any, the parent and child process should share. The clone() SC in turn calls do fork(), which is defi ned in kernel/fork.c. This function calls copy process(). Depending on the flags passed to clone(), copy process() then either duplicates or shares resources. If copy process returns successfully, the new child is
run. Deliberately, kernel runs the child process rst. In the common case of simply calling exec() immediately, this eliminates any copy-on-write overhead if the parent ran fi rst and began writing to the address space.
Linux implementation of threads:
To the Linux kernel, there is NO concept of a thread. A thread is merely a process that shares certain resources with other processes.
Threads are created like normal tasks, with the exception that the clone() system call
is passed flags corresponding to specifi c resources to be shared:
e.g., clone(CLONE_VM | CLONE_SIGHAND, 0);
results in behaviour identical to a normal fork(), except that the address space, and signal handlers are shared.( flags used in clone() are de ned in <linux/sched.h>.)
pthreads (POSIX Threads):
is a thread function library provided free with linux. The user can use the functions from this library to write threaded codes. The source program must be compiled with -lpthread to link with the thread library.
Code example:
#include <stdio.h>
#include <pthread.h>
#define ARRAYSIZE 1000
#define THREADS 2
void *slave(void *myid);
/* shared data */
int data[ARRAYSIZE]; /* Array of numbers to sum */
int sum = 0;
pthread_mutex_t mutex; /* mutually exclusive lock variable */
int wsize; /* size of work for each thread */
/* end of shared data */
void *slave(void *myid)
{
int i,low,high,myresult=0;
low = (int) myid * wsize;
high = low + wsize;
for (i=low;i<high;i++)
myresult += data[i];
/*printf("I am thread:%d low=%d high=%d myresult=%d \n",
(int)myid, low,high,myresult);*/
pthread_mutex_lock(&mutex);
sum += myresult; /* add partial sum to local sum */
pthread_mutex_unlock(&mutex);
return;
}
main()
{
int i;
pthread_t tid[THREADS];
pthread_mutex_init(&mutex,NULL); /* initialize mutex */
wsize = ARRAYSIZE/THREADS; /* wsize must be an integer */
for (i=0;i<ARRAYSIZE;i++) /* initialize data[] */
data[i] = i+1;
for (i=0;i<THREADS;i++) /* create threads */
if (pthread_create(&tid[i],NULL,slave,(void *)i) != 0)
perror("Pthread_create fails");
for (i=0;i<THREADS;i++) /* join threads */
if (pthread_join(tid[i],NULL) != 0)
perror("Pthread_join fails");
printf("The sum from 1 to %i is %d\n",ARRAYSIZE,sum);
}
Notes:
pthread create(tid, attr, func, arg): Creates a new thread of control that executes concurrently with the calling thread. The new thread applies the function "func" passing it "arg"
"tid": thread id
"attr": An attribute structure that governs how the thread behaves. Using NULL will use default attributes.
Uses the clone system call.
pthread join(tid, status): Suspends the execution of the calling thread until the thread identifi ed by "tid" terminates. "status" is a reference to a location where the completion status of the waited upon thread will be stored.
A mutex is a mutual exclusion device and is useful for protecting shared data structures from concurrent modifi cations, and implementing critical data structures and monitors.
A mutex has two possible states: unlocked (not owned by any thread), and locked(owned by one thread). A mutex can never be owned by two di erent threads simultaneously. A thread attempting to lock a mutex that is already locked by another thread is suspended until the owning thread unlocks the mutex fi rst.