线程的简单解析

10 篇文章 2 订阅

一、线程基本概念
线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
线程和进程的区别在于, 子进程和父进程有不同的代码和数据空间, 而多个线程则共享数据空间,每个线程有自己的执行堆栈和程序计数器为其执行上下文。多线程主要是为了节约CPU时间,发挥利用,根据具体情况而定.线程的周期新建就绪运行阻塞死亡线程调度与优先级有线程进入了就绪状态,需要有线程调度程序来决定何时执行,根据优先级来调度。
线程组每个线程都是一个线程组的一个成员,线程组把多个线程集成一个对象,通过线程组可以同时对其中的多个线程进行操作。在生成线程时必须将线程放在指定的线程组,也可以放在缺省的线程组中,缺省的就是生成该线程的线程所在的线程组.一旦一个线程加入了某个线程组,不能被移出这个组。守护线程是特殊的线程,一般用于在后台为其他线程提供服务。
isDaemon():判断一个线程是否为守护线程.
setDaemon():设置一个线程为守护线程.
二、Linux下线程有特点

Linux的线程是通过进程来模拟的,也就是说Linux里的线程本质上就是进程。

Linux的线程机制是通过内核和库混合实现的,所以线程的实现在Linux的核心态和用户态都有执行,内核实现线程/进程的调度,libpthread库实现线程之间的同步。这也就是为什么多线程程序需要连接一个libpthread库的原因。

Linux程序如果用pthread_create启动一个新的线程,实际上启动了两个轻量进程,第一个是管理线程,第二个才是真正做事情的线程。但是后续新创建的线程就不需要再创建管理线程了。源码如下

Linux这种用进程模拟线程的方式,和signal机制不一致,signal是发给进程的,但是在linux里,往一个进车发送signal,实际上只有一个线程处理这个signal。

Linux的进程机制实现的很好,进程间调度的overhead很小。
三、线程与进程的区别
进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成 a,b,c等多个块组合而成。那么这里具体的执行就可能变成:程序A得到CPU =》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。
线程在进程内部运行(地址空间中),我们可以把一个进程当作是只有一个线程。
线程的私有: 1. 私有栈结构,保证了线程之间互不干扰。 2. 硬件上下文信息,因为线程允许被切换,保护了上下文。

四、线程控制
首先介绍我们用到的函数,
1).线程创建 pthread_create,创建成功返回0,失败返回错误号。

#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

2)线程终止
1.return 返回;
2,调用pthread_cancel,源码如下:

 #include <pthread.h>
int pthread_cancel(pthread_t thread);

3,。调用pthread_exit,代码如下:

 #include <pthread.h>
void pthread_exit(void *retval);

2) . 线程等待
pthread_join 函数,成功返回0,错误返回错误号。

#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态也不相同,总结如下:
1.如果thread线程通过return返回,value_ptr存放返回值。
2.如果调用pthread_cancel终止,存放PTHREAD_CANCELED.
3.如果线程自己调用pthread_exit终止自己,存放pthread_exit的参数。

线程控制代码
1.创建

#include <stdio.h>

void* thread_run(void *arg){
    while(1){
        printf("new thread: tid: %u  pid: %d\n", pthread_self(), getpid());
        sleep(1);
    }

}
int main()
{
    pthread_t id;
    pthread_create(&id, NULL, thread_run, NULL);//线程创建
    while(1){
        printf("main thread: tid: %u  pid: %d\n", pthread_self(), getpid());
        sleep(1);
    }

    return 0;
}

2)线程等待

#include <pthread.h>
#include <stdio.h>


void* thread_run(void* arg){  //线程1
    return (void*)1;
}
void* thread_run1(void *arg){  //线程2
    while(1){
        printf("tid: %d\n", pthread_self());
        sleep(1);
    }
    return NULL;
}

void* thread_run2(void* arg){   //线程3
    pthread_detach(pthread_self());
    printf("sss\n");
}
int main()
{
    pthread_t id;
    pthread_create(&id, NULL, thread_run, NULL); //线程创建
    void* val;
    sleep(3);
    pthread_cancel(id);    //线程终止
    pthread_join(id, &val); //线程等待
    printf("tid: %d, val: %d\n", id, (int)val);

    pthread_create(&id, NULL, thread_run1, NULL);
    sleep(3);
    pthread_cancel(id);
    pthread_join(id, &val);
    printf("tid: %d, id: %d\n", pthread_self(), (int)id);
    printf("tid: %d, val: %d\n", pthread_self(), (int)val);

    pthread_create(&id, NULL, thread_run2, NULL);
    return 0;
}

五、线程分离与结合
在任何一个时间点上,线程是可结合的(joinable),或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死;在被其他线程回收之前,它的存储器资源(如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。
线程的分离状态决定一个线程以什么样的方式来终止自己。在上面的例子中,我们采用了线程的默认属性,即为非分离状态(即可结合的,joinable,需要回收),这种情况下,原有的线程等待创建的线程结束;只有当pthread_join()函数返回时,创建的线程才算终止,才能释放自己占用的系统资源。而分离线程不是这样子的,它没有被其他的线程所等待,自己运行结束了,线程也就终止了,马上释放系统资源。程序员应该根据自己的需要,选择适当的分离状态。
设置线程分离状态的函数为
pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
第二个参数可选为PTHREAD_CREATE_DETACHED(分离线程)和 PTHREAD _CREATE_JOINABLE(非分离线程)。这里要注意的一点是,如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。
分离线程的好处:
(1) 不用等待;
(2) 有多余的时间做其他事;
(3) 自动释放资源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值