进程与线程区别

Processes

  • 一个基本的运算单元
  • 一个地址空间
  • 至少一个执行线程

Thread

  • 轻量级进程
  • 线程有自己的指令指针和本地变量的副本,并且独立于其他线程执行

区别

线程不同于进程

  • 每个线程必须与单个进程相关联
  • 虽然进程中的每个线程都有自己的局部变量副本,但一个进程中的所有线程共享访问全局变量的唯一副本
  • 一个进程中的所有线程共享操作系统分配给进程的资源。
    • 如果一个线程打开一个文件并获得一个描述符,其他线程可以选择访问文件的描述符。
    • 类似地,如果一个线程关闭一个描述符,那么其他线程都不能继续使用它

本地变量规则

  • 当多个进程或线程同时执行一段代码时,每个进程或线程都会创建与其代码相关的变量的独立副本(本地变量)

全局变量规则

  • 每个进程创建一个全局变量的副本,但单个进程中的多个线程共享进程的全局变量。

实现

为了在UNIX中创建一个新进程,一个程序调用系统函数fork

  • fork将正在运行的程序划分为两个相同的进程,两个进程在同一代码中的同一位置执行
  • 两个进程继续运行,就像两个用户同时启动了两个应用程序副本一样。
#include <unistd.h>
pid_t fork(void); /* 返回子进程ID 错误返回-1 error记录错误*/

fork返回值在原来与新建的进程中是不同的,在原来进程中返回的是子进程的PID ,而在(新建的)子进程中返回值是0

进程的实现并不能实现并行,只能是并发,(同时开始,CPU时间分片式的运行各自代码)。所以就会有进程间的切换开销。当每个子进程的执行任务时间较短,但是进程很多时就会造成这种开销更大。

所以通过PID让父子进程执行不同的代码。

switch( pid ) {
case -1:
perror("fork failed");
exit(-1);
case 0: /* child */

printf("Hello, I am child of %d. My PID is \n", getppid(), getpid());
break;


default: /* parent */
printf("Hello, I am parent of %d. My PID is \n", pid, getpid());


}


select

  • 允许程序询问操作系统哪些I/O设备已准备好使用,
  • 告诉内核,让内核监听设备的可操作性,解放程序主动监听。
  • 允许一个进程去管理并发I/O;

线程使用

创建和收获线程

  • pthread_create()
  • pthread_join()
#include <pthread.h>
int pthread_create(

pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*),
void *restrict arg

);

  • 参数
    • 第一个参数为指向线程标识符的指针。
    • 第二个参数用来设置线程属性。如果attr为NULL,则应使用默认属性。 如果attr指定的属性稍后被修改,则线程的属性不会受到影响。
    • 第三个参数是线程运行函数的起始地址。
    • 最后一个参数是运行函数的参数。

函数指针: 返回类型(* 函数名称)(参数)
指针函数: 返回类型 * 函数名称(参数)

线程创建属性

参考文章

  • pthread_create()中的attr参数是一个结构指针,结构中的元素分别对应着新线程的运行属性,主要包括以下几项:

    • __detachstate, 表示新线程是否与进程中其他线程脱离同步,如果置位则新线程不能用pthread_join()来同步,且在退出时自行释放所占用的资源。缺省为 PTHREAD_CREATE_JOINABLE状态。这个属性也可以在线程创建并运行以后用pthread_detach()来设置,而一旦设置为 PTHREAD_CREATE_DETACH状态(不论是创建时设置还是运行时设置)则不能再恢复到 PTHREAD_CREATE_JOINABLE状态。

    • __schedpolicy,表示新线程的调度策略,主要包括 SCHED_OTHER(正常、非实时)、SCHED_RR(实时、轮转法)和 SCHED_FIFO(实时、先入先出)三种,缺省为SCHED_OTHER,后两种调度策略仅对超级用户有效。运行时可以用过 pthread_setschedparam()来改变。

    • __schedparam,一个struct sched_param结构,目前仅有一个sched_priority整型变量表示线程的运行优先级。这个参数仅当调度策略为实时(即SCHED_RR 或SCHED_FIFO)时才有效,并可以在运行时通过pthread_setschedparam()函数来改变,缺省为0。

    • __inheritsched, 有两种值可供选择:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED,前者表示新线程使用显式指定调度策略和 调度参数(即attr中的值),而后者表示继承调用者线程的值。缺省为PTHREAD_EXPLICIT_SCHED。

    • __scope, 表示线程间竞争CPU的范围,也就是说线程优先级的有效范围。POSIX的标准中定义了两个值: PTHREAD_SCOPE_SYSTEM和PTHREAD_SCOPE_PROCESS,前者表示与系统中所有线程一起竞争CPU时间,后者表示仅与同 进程中的线程竞争CPU。目前LinuxThreads仅实现了PTHREAD_SCOPE_SYSTEM一值。

    • pthread_attr_t结构中还有一些值,但不使用pthread_create()来设置。

  • 为了设置这些属性,POSIX定义了一系列属性设置函数,包括

    pthread_attr_init()、pthread_attr_destroy()和与各个属性相关的pthread_attr_get—/pthread_attr_set—函数。

线程属性

  • pthread_attr_init()
  • pthread_attr_destroy()
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
int pthread_attr_destroy(pthread_attr_t *attr);
int pthread_attr_setdetachstate(pthread_attr_t *attr,
int detachstate);

确定线程ID

  • pthread_self()
#include <pthread.h>
pthread_t pthread_self(void);

终止线程

  • pthread_exit()
  • Pthread_cancel()
#include <pthread.h>
void pthread_exit(void *value_ptr);

线程互斥

#include <pthread.h>

pthread_mutex_init(mutex, attrs) // create mutex semaphore
pthread_mutex_destroy(mutex) // delete a mutex
pthread_mutex_lock(mutex)//lock the mutex; block if locked
pthread_mutex_trylock(mutex) //lock the mutex; fail if locked
pthread_mutex_unlock(mutex) // unlock the mutex

_____________________

#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutex_init(
pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;




int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

使用

/*声明互斥变量*/

pthread_mutex_t mutex;
/* 初始化呢互斥变量 由互斥量承担锁的操作 */
pthread_mutex_init(&mutex, NULL);

/*使用*/

pthread_mutex_lock(&mutex); /* 获取互斥锁 */
/* 注意,这里以防线程的抢占,以造成一个线程在另一个线程sleep多次访问互斥资源,所以sleep要在得到互斥锁后调用. */

sleep (1);
/*临界资源*/
gnum++;
printf ("Thread_1 add one to num:%d/n", gnum);


pthread_mutex_unlock(&mutex); /* 释放互斥锁. */