• Linux 进程与线程一(创建-关闭线程)


    进程是一个实体。每一个进程都有他自己的内存地址段(heap,stack等等)
    进程是执行中的程序。
    程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体。
    进程是操作系统中最基本、重要的概念。
    线程,又是被称为轻量级进程(Lightweight Process LWP),是程序执行的最小单元。
    每一个程序都至少有一个线程,若程序只有一个线程,那么就是程序本身。
    单线程的进程可以简单的认为只有一个线程的进程。
    一个进程在同一时间只做一件事,有了多线程后一个进程同一时间可以做多件事。
    每个线程可以处理不同的事务。
    无论系统有几个CPU,即使进程运行在单CPU上,多线程也可以是进程并发处理多个事务。
    一个线程阻塞不会影响到另一个线程。
    多线程的进程可以尽可能的利用系统CPU资源。
    但也不是线程越多越好,线程越好,CPU分配给每个线程的时间片就越少。
    线程包含了表示进程内执行环境必须的信息,包括标识线程的线程ID,一组寄存器值,栈,调度优先级和策略,信号屏蔽字,errno变量以及线程私有数据,
    对于内存,堆内存和代码区一般属于一个进程的,但是栈却是属于一个线程的,每个线程都拥有一个独立的栈errno也是属于单个线程的,每个线程中的errno是独立的。 进程内所有的信息对于线程都是共享的,包括执行代码,全局变量,和堆内存,栈以及文件描述符。 线程标识
    --就像每个进程有个进程ID一样,线程也有自己的ID。 --进程ID用pid_t来表示,他是一个unsigned int. --线程可以通过pthread_t表示,pthread_t不能把它当整数处理。 --线程可以通过pthread_self()函数获得自身的线程ID
    线程创建
    --在进程中只有一个控制线程
    --程序开始运行的时候每个进程只有一个线程,它是以单线程方式启动的,在创建多个线程以前,进程的行为与传统的进程没有区别
    --gcc在链接的时候需要增加-lpthread选项(pthread是共享库文件)。
    --创建一个线程调用pthread_create函数。
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
    如果pthread_create成功返回,有thread指向的内存单元被设置为新创建线程的线程ID。
    attr参数用于定制各种不同的线程属性。
    新创建的线程从start_routine函数地址开始执行,该函数只有一个void *参数,
    如果需要向start_routine函数传递多个参数,就需要把这些参数放到一个结构中,然后把这个结构的地址作为void
    *传入。 线程创建的时候不能保证哪个先运行。 pthread_create函数成功返回0,失败返回非0,并且更新errno。 --注意:每个线程都拥有一份errno副本,不同的线程拥有不同的errno
    //线程间的栈数据交互盲点
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <unistd.h>
    #include <errno.h>
    #include <pthread.h>
    
    void * func(void *arg)
    {
        int num=*(int *)arg;
        /*
          此时程序会报错,无法获取num的值
          这是因为num在线程的栈内存中,arg指针本来是threadcreate()函数中a和b的指针,
          但是a,b是个临时变量,在控制线程的栈内存中,当执行完threadcreate()函数之后,变量a和b就会被系统释放
          此时我们在另外一个线程中取a的值就变得不可预期,因为此时a有可能已经被释放了,
          解决方案:可以在进程的堆内存上创建变量a和b,这样在另一个线程中释放,就没有问题了
         */
        printf("num is %d
    ",num);
        return NULL;
    }
    
    void threadcreate()
    {
        pthread_t thr1,thr2;
        int a=1,b=2;
        if(pthread_create(&thr1,NULL,func,&a)!=0)
        {
            printf("create thread failed!
    ");
            return;
        }
        if(pthread_create(&thr2,NULL,func,&b)!=0)
        {
            printf("create thread failed!
    ");
            return;
        }
    }
    
    
    int main(int arg,char *args[])
    {
        threadcreate();
        sleep(2);
        return 0;
    }
    .SUFFIXES:.c .o
    CC=gcc
    SRCS=tec01.c
    OBJS=$(SRCS:.c=.o)
    EXEC=tec
    
    start:$(OBJS)
        $(CC) -lpthread -o $(EXEC) $(OBJS)
        @echo "^_^-----OK------^_^"
    .c.o:
        $(CC) -Wall -g -o $@ -c $<
    clean:
        rm -f $(OBJS)
        rm -f $(EXEC)
    线程终止
    --任一线程调用了exit函数,整个进程就会终止。
    --如果信号默认动作是终止进程,那么信号发送到该进程,整个进程也会被终止。
    单个线程通过以下三种方式退出
    --线程只是从启动函数中返回,返回值是线程的退出码
    --线程可以被同一进程中的其他线程取消。
    --线程调用pthread_exit。
    void pthread_exit(void * arg);
    arg是个无类型指针,该指针会被其他线程调用pthread_join捕捉。
    在线程的子函数中调用pthread_exit()函数,线程也会退出,这点跟exit()函数相同。
    线程之间是异步的,无法确定哪个线程先执行。
    进程内的信号捕捉一般在控制线程内进行
    pthread_create()函数的第四个参数对应回调函数的参数
  • 相关阅读:
    mysql 日志
    mysql 事务中的锁
    mysql 事务的日志
    mysql 核心事务特性
    mysql 断电导致表打不开解决方案
    mysql 数据库逻辑升级
    mysql innodb存储引擎的表空间
    IDEA常用代码模板
    springcloud-GateWay常用的Predicate
    springcloud-GateWay配置动态路由
  • 原文地址:https://www.cnblogs.com/zhanggaofeng/p/5860052.html
Copyright © 2020-2023  润新知