Linux下多進程多線程混合開發框架

    多進程和多線程的概念相信大家都大致清楚,就不去百度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;
}

    每個進程都創建多個線程,其中進程裏面的多個線程包含對一些同一資源的調用,所以需要用到鎖等。最經典的可以看一下進程1的線程,是之前看到的一個教授接見學生的demo,囊括了線程的基本知識。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章