C之多子进程与多线程

进程线程是操作系统中的重要机制,是实现程序管理和并发的重要手段。早期操作系统进程是最小执行单位,而在现代线程级操作系统中,线程是最小执行单位。

线程隶属于进程,进程是执行线程的容器,线程使得编写并发程序更简单。

下面两例改编自Wikipedia,分别演示了C语言中进程与线程的相关操作。

进程

child_process.c

/**
 * @{file} child_process.c
 *
 * forking processes test
 */

#include <stdio.h>
#include <stdlib.h>       // NOTE: EXIT_SUCCESS / EXIT_FAILURE
#include <unistd.h>       // NOTE: fork / sysconf
#include <sys/wait.h>     // NOTE: waitpid

#define ANSI_COLOR_RED     "x1b[31m"
#define ANSI_COLOR_GREEN   "x1b[32m"
#define ANSI_COLOR_RESET   "x1b[0m"

/**
 * @{function} fork processes
 * @{params} a child process num
 * @{return} none
 */
void fork_processes(unsigned num) {
  pid_t pid = fork();

  switch (pid) {
    case -1:
      perror("fork failed");
      exit(EXIT_FAILURE);                               // NOTE: C standard exit for the parent process
    case 0:
      printf(ANSI_COLOR_RED "Hello from the child process %dn" ANSI_COLOR_RESET, num);
      _exit(EXIT_SUCCESS);                              // NOTE: POSIX _exit for the child process
    default: {
      printf(ANSI_COLOR_GREEN "The parent process is waitting for pid %dn" ANSI_COLOR_RESET, pid);
      // To suspend execution until the child has exited.
      int status;
      (void)waitpid(pid, &status, 0);
    }
  }
}

int main(void) {
  unsigned num_of_cpus = sysconf(_SC_NPROCESSORS_ONLN); // Get the number of logical CPUs.

  // fork child processes with the same number of cpuss
  for (size_t index = 0; index < num_of_cpus; index++) {
    fork_processes(index);
  }

  printf("All child processes completed successfullyn");

  return EXIT_SUCCESS;                                  // NOTE:Only executed in the parent process
}

运行结果如下图:

forking_process
forking_process

当然,从上图我们可以看出这个多进程程序并没有体现出并行性(即输出不是混乱的)。这是因为我们在fork子进程时,每fork一个子进程,父进程就wait该子进程直到其退出,然后才fork下一个,所以才会出现这种情况。

显然我们这个示例程序只是个“假的”多进程,如果要真正并行,父进程应该fork完就不管,最后再一起wait

线程

threads.c

/**
 * @{file} threads.c
 *
 * create threads test
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>

#define ANSI_COLOR_RED     "x1b[31m"
#define ANSI_COLOR_GREEN   "x1b[32m"
#define ANSI_COLOR_RESET   "x1b[0m"

void* create_thread(void* argument) {
  int passed_in_value;

  passed_in_value = *((int*) argument);
  printf(ANSI_COLOR_RED "Hello form thread %d!n" ANSI_COLOR_RESET, passed_in_value);

  return NULL;
}

int main(int argc, char** argv) {
  unsigned num_of_cpus = sysconf(_SC_NPROCESSORS_ONLN);

  pthread_t threads[num_of_cpus];
  int thread_args[num_of_cpus];
  int result_code;

  // create all threads one by one
  for (size_t index = 0; index < num_of_cpus; ++index) {
    thread_args[ index ] = index;
    printf(ANSI_COLOR_GREEN "In main: creating thread %dn" ANSI_COLOR_RESET, index);
    result_code = pthread_create(&threads[index], NULL, create_thread, &thread_args[index]);
    assert(!result_code);
  }

  // wait for each thread to complete
  for (size_t index = 0; index < num_of_cpus; ++index) {
    // block until thread 'index' completes
    result_code = pthread_join(threads[index], NULL);
    assert(!result_code);
    printf(ANSI_COLOR_GREEN "In main: thread %d has completedn" ANSI_COLOR_RESET, index);
  }

  printf("In main: All threads completed successfullyn");
  exit(EXIT_SUCCESS);
}

线程同子进程一样,具有异步特性,不过线程开销小。运行上述两次代码:(注:pthread.h并非原声linux库,所以编译时加上-lpthread,静态链接pthread库)

threads-1
threads-1
threads-2
threads-2

可见运行结果并不一致。

参考:

  1. Wikipedia – Fork (system call)
  2. Wikipedia – POSIX Threads
  3. Die.net – pthread_create(3) – Linux man page
  4. 维基百科 – 进程
  5. 维基百科 -线程

作者: V

Web Dev

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s