• 线程学习笔记(一)


     

    1.什么是线程?

    老师说过学好操作系统(Operating System)最重要的三个概念就是文件、虚存和进程了。之前已经学习过进程,因此对于线程的概念就比较好理解了。

    进程是一个执行实体,操作系统是以进程为单位分配资源。在一个执行空间内可以用多个小型进程并发来完成不同的任务,这种小型的进程称之为线程。进程是一个比较大的概念,线程是一个比较具体化的小的概念,比如一个进程需要完成这样一个任务,读出用户收到的数据,将这些数据进行排序,再将这些数据输出,这是一个进程要完成的任务,这个进程中可以有三个线程,分别负责读数据,数据排序,输出数据。从上边的举例我们可以看出来,操作系统中真正负责执行的线程,进程只是一个分配资源的实体。

    2.线程的优势

    我们先比较一下线程和进程,线程之于进程就像进程之于操作系统。从操作系统层面来看,执行的实体是进程,引入了线程的概念之后,执行的实体是线程。可以这样理解,他们都是执行实体。

    相对于进程来说,线程的最大优势就是并行性强,在一个进程空间中可以并发进行多个线程,大大的提高程序的效率。总结来说有两个优势:

    1.线程共享进程地址空间内的所有资源,因此线程之间的通信很方便,同样的任务如果用多进程的编程模型,必须使用进程间的通信才可以,相比之下效率低了很多。

    2.多线程处理不同的任务,提高程序并发性,提高程序效率。在一个排序实例中,待排序数据过于庞大,无法一次性读入内存操作,需要先将数据读入内存,再排序,再输出这样一个循环,大部分的时间浪费在读入和输出上了,如果用多进程编程,一个进程负责读数据,一个进程负责排序,一个进程负责输出数据,这样效率就会提高很多。

    3.线程标识符

    同进程一样,线程也有自己的ID,数据类型是pthread_t,本质上也是一个无符号的整形。关于线程ID有两个函数要知道, pthread_self() 函数功能是得到线程ID的函数, pthread_equal(pthread_t tid1, pthread_t tid2) 函数的功能是比较tid1和tid2两个线程ID是否相等,相等函数返回0,不等返回非0值。

    4.创建线程

    (1)创建线程

    Linux环境下使用 pthread_create(pthread_t *restrict tidp, const pthread_attr_t * restrict attr, void *(*start_rtn)(void *), void(*restrict arg)) 函数创建线程。

    头文件:        #include <pthread.h> 

    参数说明:     pthread_t *restrict tidp :指向线程标识符的指针,函数返回时,tidp指向内核分配给线程的ID;

            const pthread_attr_t * restrict attr :设置线程属性,如果不想特别指定线程属性,一般设置为NULL;

            void *(*start_rtn)(void *) :线程运行函数的起始地址,start_rtn是一个函数指针,指向函数的返回值是一个void类型的指针,函数参数也是一个void类型的指针;

                     void(*restrict arg) :运行函数start_rtn的参数,是一个void类型的指针。

    返回值:成功创建进程返回值为0,失败返回错误编号,用perror()函数将编号映射为容易理解的描述性语言。

    函数功能:创建一个新线程,并且指明线程属性。创建新线程的同时执行线程体函数。线程体函数根据自己需求定制。

    示例程序:创建线程并打印其线程

    #include <stdio.h>
    
    #include <stdlib.h>
    
    #include <pthread.h>
    
    /* 线程函数,打印进程ID和线程ID */
    
    void * thfn(void * arg)
    
    {
    
           pid_t pid;                     /* 进程ID */
    
           pthread_t tid;               /* 线程ID */
    
           pid = getpid();                     /* 得到进程ID */
    
           tid = pthread_self();      /* 得到线程ID */
    
           /* 将两个ID转换为无符号整数打印 */
    
           printf("the new thread: pid is: %u, tid is: %u
    ", (unsigned int)pid,
    
           (unsigned int)tid);
    
           return NULL;
    
    }
    
    int main(void)
    
    {
    
           pid_t pid;
    
           int err;
    
           pthread_t tid, mtid;
    
           pid = getpid();
    
           mtid = pthread_self();                                            /* 得到主线程的线程ID */
    
           err = pthread_create(&tid, NULL, thfn, NULL); /* 创建线程,如果出错
    
                                                                                               err保存错误号 */
    
           /* 错误号和errno一样,可以由strerror函数将编号映射为容易理解的描述性语言 */
    
           if(err != 0){
    
                  /* 不能使用perror函数,因为错误号不在errno变量内 */
    
                  printf("can’t create thread %d
    ", strerror(err));
    
                  exit(1);    
    
           }
    
           /* 休眠一秒钟,保证新创建的线程在主线程之前被调用 */
    
           sleep(1);
    
           /* 打印主线程ID和进程ID */
    
           printf("the main thread: pid is: %u, tid is: %u
    ", (unsigned int)pid,
    
           (unsigned int)mtid);
    
           return 0;
    
    }
  • 相关阅读:
    django的命令, 配置,以及django使用mysql的流程
    vue中局部组件的使用
    Chapter14【Collection、泛型】
    泛型
    集合遍历的方式(迭代器和增强for)
    Collection集合
    集合
    数组
    包装类
    基本类型与字符串之间的转换
  • 原文地址:https://www.cnblogs.com/Mr--Yang/p/6286889.html
Copyright © 2020-2023  润新知