多進程和多線程的概念相信大家都大致清楚,就不去百度copy了。這裏引用一個比喻來描述下多進程和多線程:
多進程是立體交通系統,雖然造價高,上坡下坡多耗點油,但是不堵車。
多線程是平面交通系統,造價低,但紅綠燈太多,老堵車。
我們現在都開跑車,油(主頻)有的是,不怕上坡下坡,就怕堵車。
在多進程開發中,每個進程互相獨立,不影響主程序的穩定性,子進程崩潰沒關係;最好是多進程和多線程結合,即根據實際的需要,每個CPU開啓一個子進程,這個子進程開啓多線程可以爲若干同類型的數據進行處理。
需要提及的一點是,首先對於不同進程的線程而言,他們沒有什麼關係的(代碼段、數據段等都不同),所以不能通過全局變量來通信。但是對於同一進程內的線程,他們是可以通過全局變量來通信的。同一進程內的線程,他們都共享進程的代碼段、數據段、BSS段。頁目錄和頁表應該是使用進程的頁目錄和頁表。
linux fork()子父進程變量共享情況,共享代碼段
子進程會拷貝父進程的所有資源,變量。
注意:子進程拷貝了父進程數據空間、堆、棧等資源的副本,
父子進程間不共享這些存儲空間,共享的空間只有代碼段,
子進程修改一個全局變量,父進程的這個全局變量不會改變,因爲是一個副本。
所以進程之間可以通過共享內存、消息隊列等方式進行通信。在實際的項目開發中,這個用得很多,現在也有一些不錯的開源庫提供給大家調用。
下面給出一個多進程結合多線程的開發案例,供大家參考:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/time.h>
#define NUM_THREADS 6
#define ID_BASE 101
#define CHAIR_COUNT 3
#define STUDENT_COUNT 25
#define MAX_MEETING_DURATION 5
#define OFFICE_HOUR_DURATION 60
#define BSIZE 4
#define NUMITEMS 30
typedef struct {
char buf[BSIZE];
int occupied;
int nextin, nextout;
pthread_mutex_t mutex;
pthread_cond_t more;
pthread_cond_t less;
} buffer_t;
buffer_t buffer;
#define NUM_THREADS2 2
pthread_t tid[NUM_THREADS2]; /* array of thread IDs */
#define NTHREADS 4
#define N 1000
#define MEGEXTRA 1000000
pthread_attr_t attr;
#define NUM_THREADS5 8
char *messages[NUM_THREADS5];
//-------------------------------------------------------------------------
/*進程1的線程*/
//--------------------------------------------------------------------------
int chairs[CHAIR_COUNT]; // circular buffer of chairs
pthread_mutex_t chairMutex; // mutex protects chairs and wait count
pthread_mutex_t printMutex; // mutex protects printing
sem_t filledChairs; // professor waits on this semaphore
struct itimerval profTimer; // professor's office hour timer
time_t startTime;
int in = 0, out = 0;
int meetingId = 0;
int arrivalsCount = 0;
int waitCount = 0;
int leavesCount = 0;
int meetingsCount = 0;
int parforeCount = 0;
int firstPrint = 1;
// Print a line for each event:
// elapsed time
// who is meeting with the professor
// who is waiting in the chairs
// what event occurred
void print(char *event)
{
time_t now;
time(&now);
double elapsed = difftime(now, startTime);
int min = 0;
int sec = (int) elapsed;
if (sec >= 60) {
min++;
sec -= 60;
}
// Acquire the mutex lock to protect the printing.
pthread_mutex_lock(&printMutex);
if (firstPrint) {
printf("TIME | MEETING | WAITING | EVENT\n");
firstPrint = 0;
}
// Elapsed time.
printf("%1d:%02d | ", min, sec);
// Who's meeting with the professor.
if (meetingId > 0) {
printf("%5d |", meetingId);
}
else {
printf(" |");
}
// Acquire the mutex lock to protect the chairs and the wait count.
pthread_mutex_lock(&chairMutex);
int i = out;
int j = waitCount;
int k = 0;
// Who's waiting in the chairs.
while (j-- > 0) {
printf("%4d", chairs[i]);
i = (i+1)%CHAIR_COUNT;
k++;
}
// Release the mutex lock.
pthread_mutex_unlock(&chairMutex);
// What event occurred.
while (k++ < CHAIR_COUNT) printf(" ");
printf(" | %s\n", event);
// Release the mutex lock.
pthread_mutex_unlock(&printMutex);
}
// A student arrives.
void studentArrives(int id)
{
char event[80];
arrivalsCount++;
if (waitCount < CHAIR_COUNT) {
// Acquire the mutex lock to protect the chairs and the wait count.
pthread_mutex_lock(&chairMutex);
// Seat a student into a chair.
chairs[in] = id;
in = (in+1)%CHAIR_COUNT;
waitCount++;
// Release the mutex lock.
pthread_mutex_unlock(&chairMutex);
sprintf(event, "Student %d arrives and waits", id);
print(event);
// Signal the "filledSlots" semaphore.
sem_post(&filledChairs); // signal
}
else {
leavesCount++;
sprintf(event, "Student %d arrives and leaves", id);
print(event);
}
}
// The student thread.
void *student(void *param)
{
int id = *((int *) param);
// Students will arrive at random times during the office hour.
sleep(rand()%OFFICE_HOUR_DURATION);
studentArrives(id);
return NULL;
}
int timesUp = 0; // 1 = office hour is over
// The professor meets a student (or works on ParFore).
void professorMeetsStudent()
{
// No student waiting, so work on ParFore language.
if (waitCount == 0) {
print("Professor works on ParFore");
parforeCount++;
}
if (!timesUp) {
// Wait on the "filledChairs" semaphore for a student.
sem_wait(&filledChairs);
// Acquire the mutex lock to protect the chairs and the wait count.
pthread_mutex_lock(&chairMutex);
// Critical region: Remove a student from a chair.
meetingId = chairs[out];
out = (out+1)%CHAIR_COUNT;
waitCount--;
// Release the mutex lock.
pthread_mutex_unlock(&chairMutex);
char event[80];
sprintf(event, "Professor meets with student %d", meetingId);
print(event);
// Meet with the student.
sleep(rand()%MAX_MEETING_DURATION + 1);
meetingsCount++;
sprintf(event, "Professor finishes with student %d", meetingId);
meetingId = 0;
print(event);
}
}
// The professor thread.
void *professor(void *param)
{
print("Professor opens her door");
// Set the timer for for office hour duration.
profTimer.it_value.tv_sec = OFFICE_HOUR_DURATION;
setitimer(ITIMER_REAL, &profTimer, NULL);
// Meet students until the office hour is over.
do {
professorMeetsStudent();
} while (!timesUp);
print("Professor closes her door");
return NULL;
}
// Timer signal handler.
void timerHandler(int signal)
{
timesUp = 1; // office hour is over
}
//--------------------------------------------------------------------------
/*進程3的線程*/
//--------------------------------------------------------------------------
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World!In process3, it's thread #%ld!\n", tid);
pthread_exit(NULL);
//printf("goodbye! exit thread #%ld!\n", tid);
}
//----------------------------------------------------------------------------
/*進程2的線程*/
//----------------------------------------------------------------------------
void * producer(void * parm)
{
char item[NUMITEMS]="IT'S A SMALL WORLD, AFTER ALL.";
int i;
printf("producer started.\n");
for(i=0;i<NUMITEMS;i++)
{ /* produce an item, one character from item[] */
if (item[i] == '\0') break; /* Quit if at end of string. */
pthread_mutex_lock(&(buffer.mutex));
if (buffer.occupied >= BSIZE) printf("producer waiting.\n");
while (buffer.occupied >= BSIZE)
pthread_cond_wait(&(buffer.less), &(buffer.mutex) );
printf("producer executing.\n");
buffer.buf[buffer.nextin++] = item[i];
buffer.nextin %= BSIZE;
buffer.occupied++;
/* now: either buffer.occupied < BSIZE and buffer.nextin is the index
of the next empty slot in the buffer, or
buffer.occupied == BSIZE and buffer.nextin is the index of the
next (occupied) slot that will be emptied by a consumer
(such as buffer.nextin == buffer.nextout) */
pthread_cond_signal(&(buffer.more));
pthread_mutex_unlock(&(buffer.mutex));
}
printf("producer exiting.\n");
pthread_exit(0);
}
void * consumer(void * parm)
{
char item;
int i;
printf("consumer started.\n");
for(i=0;i<NUMITEMS;i++){
pthread_mutex_lock(&(buffer.mutex) );
if (buffer.occupied <= 0) printf("consumer waiting.\n");
while(buffer.occupied <= 0)
pthread_cond_wait(&(buffer.more), &(buffer.mutex) );
printf("consumer executing.\n");
item = buffer.buf[buffer.nextout++];
printf("%c\n",item);
buffer.nextout %= BSIZE;
buffer.occupied--;
/* now: either buffer.occupied > 0 and buffer.nextout is the index
of the next occupied slot in the buffer, or
buffer.occupied == 0 and buffer.nextout is the index of the next
(empty) slot that will be filled by a producer (such as
buffer.nextout == buffer.nextin) */
pthread_cond_signal(&(buffer.less));
pthread_mutex_unlock(&(buffer.mutex));
}
printf("consumer exiting.\n");
pthread_exit(0);
}
//----------------------------------------------------------------------------
/*進程4的線程*/
void *dowork(void *threadid)
{
double A[N][N];
int i,j;
long tid;
size_t mystacksize;
tid = (long)threadid;
pthread_attr_getstacksize (&attr, &mystacksize);
printf("Thread %ld: stack size = %li bytes \n", tid, mystacksize);
for (i=0; i<N; i++)
for (j=0; j<N; j++)
A[i][j] = ((i*j)/3.452) + (N-i);
pthread_exit(NULL);
}
//----------------------------------------------------------------------------
/*進程5的線程*/
void *PrintHello5(void *threadid)
{
long taskid;
sleep(1);
taskid = (long) threadid;
printf("Thread %d: %s\n", taskid, messages[taskid]);
pthread_exit(NULL);
}
//----------------------------------------------------------------------------
int main(void)
{
//開啓守護進程
if(daemon(1, 1) < 0)
{
perror("error daemon.../n");
exit(1);
}
printf("I am daemon. pid=%d ppid=%d\n", getpid(), getppid());
//進程1
pid_t p1 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d,in parent, pid = %d\n", getpid(),getppid());
//創建5個線程
//pthread_t threads1[NUM_THREADS];
//int rc1;
//long t1;
//for(t1=1; t1<NUM_THREADS; t1++){
//printf("In process1: creating thread %ld\n", t1);
//rc1 = pthread_create(&threads1[t1], NULL, PrintHello, (void *)t1);
//if (rc1){
//printf("ERROR; return code from pthread_create() is %d\n", rc1);
//exit(-1);
//}
//}
int studentIds[STUDENT_COUNT];
int professorId = 0;
// Initialize the mutexes and the semaphore.
pthread_mutex_init(&chairMutex, NULL);
pthread_mutex_init(&printMutex, NULL);
sem_init(&filledChairs, 0, 0);
srand(time(0));
time(&startTime);
// Create the professor thread.
pthread_t professorThreadId;
pthread_attr_t profAttr;
pthread_attr_init(&profAttr);
pthread_create(&professorThreadId, &profAttr, professor, &professorId);
// Create the student threads.
int i;
for (i = 0; i < STUDENT_COUNT; i++) {
studentIds[i] = ID_BASE + i;
pthread_t studentThreadId;
pthread_attr_t studentAttr;
pthread_attr_init(&studentAttr);
pthread_create(&studentThreadId, &studentAttr, student, &studentIds[i]);
}
// Set the timer signal handler.
signal(SIGALRM, timerHandler);
// Wait for the professor to complete the office hour.
pthread_join(professorThreadId, NULL);
// Remaining waiting students leave.
meetingId = 0;
while (waitCount-- > 0) {
int studentId = chairs[out];
out = (out+1)%CHAIR_COUNT;
leavesCount++;
char event[80];
sprintf(event, "Student %d leaves", studentId);
print(event);
}
// Final statistics.
printf("\n");
printf("%5d students arrived\n", arrivalsCount);
printf("%5d students met with Prof. Fore\n", meetingsCount);
printf("%5d students left without meeting\n", leavesCount);
printf("%5d times Prof. Fore worked on ParFore\n", parforeCount);
sleep(3);
return 0; //若此處沒有return 0 p1 進程也會執行 pid_t p2=fork()語句
}
//進程2
pid_t p2 = fork();
if ( p2 == 0 )
{
printf("in child 2, pid = %d,in parent, pid = %d\n", getpid(),getppid());
//創建5個線程
//pthread_t threads2[NUM_THREADS];
//int rc2;
// long t2;
// for(t2=1; t2<NUM_THREADS; t2++){
//printf("In process2: creating thread %ld\n", t2);
//rc2 = pthread_create(&threads2[t2], NULL, PrintHello, (void *)t2);
//if (rc2){
// printf("ERROR; return code from pthread_create() is %d\n", rc2);
// exit(-1);
// }
// }
int i;
pthread_cond_init(&(buffer.more), NULL);
pthread_cond_init(&(buffer.less), NULL);
pthread_create(&tid[1], NULL, consumer, NULL);
pthread_create(&tid[0], NULL, producer, NULL);
for ( i = 0; i < NUM_THREADS2; i++)
pthread_join(tid[i], NULL);
printf("\nmain() reporting that all %d threads have terminated\n", i);
sleep(10);
return 0; //子進程結束,跳回父進程
}
//進程3
pid_t p3 = fork();
if( p3 == 0 )
{
printf("in child 3, pid = %d,in parent, pid = %d\n", getpid(),getppid());
//創建5個線程
pthread_t threads3[NUM_THREADS];
int rc3;
long t3;
for(t3=1; t3<NUM_THREADS; t3++){
printf("In process3: creating thread %ld\n", t3);
rc3 = pthread_create(&threads3[t3], NULL, PrintHello, (void *)t3);
if (rc3){
printf("ERROR; return code from pthread_create() is %d\n", rc3);
exit(-1);
}
}
sleep(10);
return 0;
}
//進程4
pid_t p4 = fork();
if( p4 == 0 )
{
printf("in child 4, pid = %d,in parent, pid = %d\n", getpid(),getppid());
pthread_t threads[NTHREADS];
size_t stacksize;
int rc;
long t;
pthread_attr_init(&attr);
pthread_attr_getstacksize (&attr, &stacksize);
printf("Default stack size = %li\n", stacksize);
stacksize = sizeof(double)*N*N+MEGEXTRA;
printf("Amount of stack needed per thread = %li\n",stacksize);
pthread_attr_setstacksize (&attr, stacksize);
printf("Creating threads with stack size = %li bytes\n",stacksize);
for(t=0; t<NTHREADS; t++){
rc = pthread_create(&threads[t], &attr, dowork, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
printf("Created %ld threads.\n", t);
pthread_exit(NULL);
sleep(10);
return 0;
}
//進程5
pid_t p5 = fork();
if( p5 == 0 )
{
printf("in child 5, pid = %d,in parent, pid = %d\n", getpid(),getppid());
pthread_t threads[NUM_THREADS5];
long taskids[NUM_THREADS5];
int rc, t;
messages[0] = "English: Hello World!";
messages[1] = "French: Bonjour, le monde!";
messages[2] = "Spanish: Hola al mundo";
messages[3] = "Klingon: Nuq neH!";
messages[4] = "German: Guten Tag, Welt!";
messages[5] = "Russian: Zdravstvuyte, mir!";
messages[6] = "Japan: Sekai e konnichiwa!";
messages[7] = "Latin: Orbis, te saluto!";
for(t=0;t<NUM_THREADS5;t++) {
taskids[t] = t;
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello5, (void *) taskids[t]);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
sleep(3);
return 0;
}
//int b;
//printf("請輸入0以退出:");
//scanf("%d",&b);
//if(b == 0)
//{
// return 0;
//}
int st1, st2,st3, st4, st5;
sleep(10);
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
waitpid( p3, &st3, 0);
waitpid( p4, &st4, 0);
waitpid( p5, &st5, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, child 3 pid = %d\n", p3);
printf("in parent, child 4 pid = %d\n", p4);
printf("in parent, child 5 pid = %d\n", p5);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
printf("in parent, child 3 exited with %d\n", st3);
printf("in parent, child 4 exited with %d\n", st4);
printf("in parent, child 5 exited with %d\n", st5);
return 0;
}