线程学习笔记

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\n", (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\n", strerror(err));

              exit(1);    

       }

       /* 休眠一秒钟,保证新创建的线程在主线程之前被调用 */

       sleep(1);

       /* 打印主线程ID和进程ID */

       printf("the main thread: pid is: %u, tid is: %u\n", (unsigned int)pid,

       (unsigned int)mtid);

       return 0;

}
时间: 2024-08-09 10:31:37

线程学习笔记的相关文章

Java线程学习笔记(二) 线程的异常捕捉

线程异常的捕捉: 正常的情况下,我们在main()方法里是捕捉不到线程的异常的,例如以下代码: public class ExceptionThread implements Runnable{ @Override public void run() { throw new NullPointerException(); } public static void main(String[] args) { ExecutorService executorService = Executors.n

Java线程学习笔记(一)

一.线程的创建方式: 老掉牙的话题了,继承 java.lang.Thread父类或者实现Runnalbe接口,这里就提一句: class Thread implements Runnable Thread也是继承了Runnable接口的,Runnable才是大哥. 重写run(),run()里放的都是具体的业务,包括对线程的具体操作. class Thread1 implements Runnable { int i; Thread1(int i) { this.i = i; } @Overri

【转】linux 用户线程、LWP、内核线程学习笔记

[好文转发---linux 用户线程.LWP.内核线程学习笔记] 在现代操作系统中,进程支持多线程.进程是资源管理的最小单元:而线程是程序执行的最小单元.一个进程的组成实体可以分为两大部分:线程集合资源集.进程中的线程是动态的对象:代表了进程指令的执行.资源,包括地址空间.打开的文件.用户信息等等,由进程内的线程共享. 线程有自己的私有数据:程序计数器,栈空间以及寄存器. Why Thread?(传统单线程进程的缺点) 1. 现实中有很多需要并发处理的任务,如数据库的服务器端.网络服务器.大容量

线程学习笔记2

对于文章里面碰到的问题,可能也是我学习1当中出现的问题,新开的线程不管委托与否都在同一个线程里面,所以新线程运行的时候,主窗体也会停住,后来想在新线程中打开窗体的思路来处理,结果碰到下面文章的问题,在多方面的查找和学习后发现有一个办法可以解决它,希望对大家有帮助. private void button7_Click(object sender, EventArgs e) { Thread thread2 = new Thread(threadPro);//创建新线程 thread2.Start

线程学习笔记(二)

5.终止线程 线程退出的方式有3种 1.线程体函数执行结束,用 pthread_create() 函数创建一个新线程的时候会执行一个函数,这个函数就是线程体函数,如果该函数执行完毕,那么线程退出,类似于住进程的 main() 函数返回. 2.线程被另一个线程取消.这种方法类似于一个进程被另一个进程调用kill()函数杀死. 3.线程自行退出,类似于线程调用一个 exit() 函数. Linux系统中使用 pthread_exit(void *rval_ptr) 函数终止线程: 头文件:  #in

线程学习笔记(EventWaitHandler)AutoResetEvent的使用

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication46 { class TwoWaySignaling { //事件等待句柄 static EventWaitHandle _ready = new AutoRese

线程学习笔记 等待句柄和线程池(摘自https://blog.gkarch.com/threading/part2.html#manualresetevent)

//如果你的应用有很多线程,这些线程大部分时间都在阻塞,那么可以通过调用ThreadPool.RegisterWaitForSingleObject来减少资源消耗.这个方法接受一个委托,它会在向等待句柄发信号时执行.当处于等待状态时,它不会浪费线程资源: static ManualResetEvent _starter = new ManualResetEvent (false); public static void Main() { RegisteredWaitHandle reg = Th

lua协程----ngx-lua线程学习笔记

--[[ - @desc lua数据输出 - @param string 字符串 - return string --]] function dump(v) if not __dump then function __dump(v, t, p) local k = p or ""; if type(v) ~= "table" then table.insert(t, k .. " : " .. tostring(v)); else for key

Java线程学习笔记(两) 线程异常处理

线程捕获异常: 情况下,我们在main()方法里是捕捉不到线程的异常的,比例如以下面代码: public class ExceptionThread implements Runnable{ @Override public void run() { throw new NullPointerException(); } public static void main(String[] args) { ExecutorService executorService = Executors.new