linux线程终止 - CSDN
  • 一个进程可以并发线程,每个线程执行不同的任务 比如四个人在一个房子里打麻将,创建一个新进程就相当于是在开一个房间,而创建一个新线程是在原有的房间中增加一个人而已 线程的优点 1.创建一个新的...

    线程

    1.是操作系统能够进行调度的最小单位
    2.线程被包含在进程之中,是进程中的实际运作单位
    3.一个线程指的是进程中一个单一顺序的控制流
    4.一个进程可以并发多个线程,每个线程执行不同的任务

    比如四个人在一个房子里打麻将,创建一个新进程就相当于是在开一个房间,而创建一个新线程是在原有的房间中增加一个人而已
    这里写图片描述

    线程的优点

    1.创建一个新的线程的代价要比创建一个新进程的代价小得多
    2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
    3.线程占有的资源要比进程少
    4.线程之间共享数据更容易(线程是在一个房间中,所以相互通信比较容易,而进程之间通话需要跑到另一个房间)

    线程的缺点

    1.编码/调试难度提高
    因为线程之间谁先执行不确定,在一个是共享资源的问题
    2.缺乏访问控制
    一个线程崩溃,会导致整个进程都异常终止,一个线程中调用某些函数,会影响整个进程

    进程与线程的区别

    1.进程:进程(或者任务)是资源分配的基本单位
    2.线程:线程(或者轻量级进程)是调度/执行的基本单位
    3.线程运行在进程中
    4.一个进程至少都有一个线程

    进程与线程中函数的对比

    这里写图片描述
    为什么线程/进程数不是越多越好?

    1.线程/进程数目达到一定程度时,就不会再提高程序的执行效率了
    2.线程/进程数目过多可能会导致进程异常终止
    3.线程/进程数目过多可能会导致线程安全问题(线程安全:多个线程竞争同一资源)

    线程创建

    pthread_create

    功能:创建一个新的线程
    头文件:#include<pthread.h>
    原型:
     int pthread_create(   pthread_t *pthread, 
                           const pthread_attr_t*attr, 
                           void*(*start_routine)(void*), 
                           void *arg  )
    参数说明:
    thread:返回线程ID,此参数是一个输出型参数
          (返回的是新创建的线程的ID)
    
    attr:设置线程的属性,attr为NULL表示使用默认属性(一般设为NULL)
        (设置的是新线程的属性)
    
    start_routine:是个函数地址,线程启动后需要执行的函数
                 (这是一个函数指针,指向线程的入口函数)
    
    arg:传给线程启动函数的参数
    
    返回值:成功返回0,失败返回错误码
    

    线程被创建后,并不能保证那个线程先执行,新创建的线程和调用线程的执行顺序不确定,由操作系统进行调度

    示例

    1.创建一个线程
    代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        printf("I am thread\n");
    }
    
    int main()
    {
        pthread_t tid;
        int ret=0;
        ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(ret!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        printf("I am main\n");
        sleep(1);
     //让主线程睡眠1秒,是为了不让此线程跑的太快使整个进程结束
     //如果主线程跑的太快,新创建的线程还没来的及执行,整个进程就已经结束了
        return 0;
    }
    

    运行结果:
    这里写图片描述

    2.使用死循环来创建线程(死循环是为了防止主线程跑的太快,而使新创建的线程没有机会执行,让它循环多次相当于是等待新线程启动和执行)
    代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        while(1)
        {
            printf("I am thread,%1x\n",pthread_self());
            sleep(1);
        }
    }
    int main()
    {
        int ret=0;
        pthread_t tid;
        ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(ret!=0)
        { 
            perror("pthread_create");
            exit(1);
        }
        while(1)
        {
            printf("I am main,%1x\n",pthread_self());
            sleep(1);
        }
        return 0;
    }

    pthread_self()是得到当前线程的ID

    线程创建函数在libpthread.so库中,所以在编译时需要将该库导入,命令如下:
    例如编译create.c
    gcc create.c -lpthread
    就是说在编译时需要加上 "-lpthread"

    运行结果:
    这里写图片描述

    线程终止

    如果需要终止某个线程,而不终止整个进程,有以下三种方法:

    1.从需要终止的线程函数中直接return
    ps:这种方法对主线程不适用,因为从main函数return相当于调用exit,会使main函数直接退出
    2.需要终止的线程可以调用pthread_exit()来终止自己
    3.一个线程可以调用pthread_cancel来终止同一进程中的其他线程

    pthread_exit()

    
    1.功能:终止线程
    
    2.原型:
    void pthread_exit(void *value_ptr)
    参数说明:
    value_ptr:不要指向一个局部变量
    
    3.返回值:
    无返回值
    

    pthread_cancel()

    1.功能:取消一个执行中的线程
    
    2.原型:
    int pthread_cancel(pthread_t thread)
    参数说明:
    thread:需要取消的线程的ID
    
    3.返回值:
    成功返回0,失败返回错误码
    

    1.直接return

    #include<unistd.h>
    #include<stdlib.h>
    #include<stdio.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        int count=0;
        (void)arg;
        while(1)
        {
            ++count;
            if(count>=5)
                return NULL;
            printf("I am thread,%1x\n",pthread_self());
            sleep(1);
        }
    }
    int main()
    {
    int ret=0;
        pthread_t tid;
    ret=    pthread_create(&tid,NULL,ThreadEntry,NULL);
    if(ret!=0)
    {
     perror("pthread_create");
     exit(1);
     }
        while(1)
        {
            printf("I am main,%1x\n",pthread_self());
            sleep(1);
        }
        return 0;
    }

    运行结果:
    这里写图片描述

    2.调用pthread_exit()

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<pthread.h>
    void*ThreadEntry(void *arg)
    {
        int count=0;
        (void)arg;
        while(1)
        {
            ++count;
            if(count>=7)
                pthread_exit(NULL);
            printf("I am thread\n");
            sleep(1);
        }
    }
    int main()
    {
        int ret=0;
        pthread_t tid;
        ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(ret!=0)
        {
            perror("ptherad_create");
            exit(1);
        }
        while(1)
        {
            printf("I am main\n");
            sleep(1);
        }
        return 0;
    }
    

    运行结果:
    这里写图片描述

    3.调用pthread_cancel()

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<pthread.h>
    void *ThreadEntry(void*arg)
    {
        (void)arg;
        while(1)
        {
            printf("I am thread\n");
            sleep(1);
        }
    }
    int main()
    {
        int ret=0;
        int count=0;
        pthread_t tid;
        ret=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(ret!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        while(1)
        {
            ++count;
            if(count>10)
                pthread_cancel(tid);
            printf("I am main\n");
            sleep(1);
        }
        return 0;
    }

    运行结果:
    这里写图片描述

    pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用manlloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数就已经退出了
    示例

    1.return返回线程函数栈上分配的变量

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        int a=10;
        int *p=&a;
        printf("I am thread\n");
        return (void*)p;
    }
    
    int main()
    {
        pthread_t tid;
        void*ret;
        int thread=0;
        thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(thread!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        printf("I am main\n");
        pthread_join(tid,&ret);
        printf("ret=%d\n",*(int*)ret);
        return 0;
    }

    这里写图片描述

    2.pthread_exit中的参数是线程函数在栈上分配的

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        int count=0;
        int a=10;
        int *p=&a;
        while(1)
        {
            ++count;
            if(count>=5)
                pthread_exit(p);
            printf("I am thread\n");
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
        void*ret;
        int thread=0;
        thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(thread!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        printf("I am main\n");
        pthread_join(tid,&ret);
        printf("ret=%d\n",*(int*)ret);
        return 0;
    }

    这里写图片描述

    malloc分配

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        int count=0;
        int *p=(int*)malloc(sizeof(int));
        *p=10;
        while(1)
        {
            ++count;
            if(count>=5)
                pthread_exit(p);
            printf("I am thread\n");
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
        void*ret;
        int thread=0;
        thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(thread!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        printf("I am main\n");
        pthread_join(tid,&ret);
        printf("ret=%d\n",*(int*)ret);
        free(ret);//malloc后记得释放
        return 0;
    }

    这里写图片描述

    全局变量

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<pthread.h>
    int a=20;
    void*ThreadEntry(void*arg)
    {
        (void)arg;
        int count=0;
        int*p=&a;
        while(1)
        {
            ++count;
            if(count>=5)
                pthread_exit(p);
            printf("I am thread\n");
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
        void*ret;
        int thread=0;
        thread=pthread_create(&tid,NULL,ThreadEntry,NULL);
        if(thread!=0)
        {
            perror("pthread_create");
            exit(1);
        }
        printf("I am main\n");
        pthread_join(tid,&ret);
        printf("ret=%d\n",*(int*)ret);
        return 0;
    }
    

    这里写图片描述

    展开全文
  • 线程终止: 1、 如果进程中的任意一个线程调用了exit,_Exit,_exit,那么整个进程就会终止 2、 从启动例程中返回,返回值是线程的退出码 3、 线程可以被同一进程中的其他线程取消 4、 线程调用pthread_exit(void *...

    线程终止:

    1、 如果进程中的任意一个线程调用了exit,_Exit,_exit,那么整个进程就会终止

    2、 从启动例程中返回,返回值是线程的退出码

    3、 线程可以被同一进程中的其他线程取消

    4、 线程调用pthread_exit(void *rval)函数,rval是退出码


    #include <stdio.h>
    #include <iostream>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    using namespace std;
    
    int method = 1;
    
    void *thread_fun(void *arg)
    {
    	//如果传到参数1,那么就采用return方式退出
    	if(method==1)
    	{
    		cout<<"new thread using return!"<<endl;
    		return (void *)1;
    	}
    	//如果传入参数2,那么就采用pthreade_xit方式退出
    	if(method==2)
    	{
    		cout<<"new thread using pthread_exit!"<<endl;
    		pthread_exit((void *)2);
    	}
    	//如果传入参数3,那么就采用exit方式退出
    	if(method==3)
    	{
    		cout<<"new thread using exit!"<<endl;
    		exit(3);
    	}
    	return 0;
    }
    
    int main(int argc, char *argv[])
    {
    	int err;
    	pthread_t tid;
    
    	err = pthread_create(&tid, NULL, thread_fun, (void *)argv[1]);
    	if(err != 0)
    	{
    		cout<<"create new  thread failed"<<endl;
    		return 0;
    	}
    	void *status;
    	pthread_join(tid, &status);
    	cout<<"main thread"<<endl;
    	cout<<"new thread's exit status: "<<(int)status<<endl;
    	return 0;
    }
    



    线程连接:

    int pthread_join(pthead_ttid, void **rval)

    调用该函数的线程会一直阻塞,直到指定的线程tid调用pthread_exit、从启动例程返回或者被取消

    参数tid就是指定线程的id

    参数rval是指定线程的返回码,如果线程被取消,那么rval被置为PTHREAD_CANCELED

    该函数调用成功会返回0,失败返回错误码

     

    调用pthread_join会使指定的线程处于分离状态,如果指定线程已经处于分离状态,那么调用就会失败

    pthread_detach可以分离一个线程,线程可以自己分离自己

    intpthread_detach(pthread_t thread);

    成功返回0,失败返回错误码


    #include <stdio.h>
    #include <iostream>
    #include <pthread.h>
    
    using namespace std;
    
    void *thread_fun1(void *arg)
    {
    	cout<<"thread 1 is runing"<<endl;
    	return (void *)1;
    }
    
    void *thread_fun2(void *arg)
    {
    	cout<<"thread 2 is runing"<<endl;
    	pthread_detach(pthread_self());
    	pthread_exit((void *)2);
    }
    
    int main()
    {
    	int err1, err2;
    	pthread_t tid1, tid2;
    	void *rval1, *rval2;
    
    	err1 = pthread_create(&tid1, NULL, thread_fun1, NULL);
    	err2 = pthread_create(&tid2, NULL, thread_fun2, NULL);
    
    	if(err1 || err2)
    	{
    		cout<<"create new thread failed"<<endl;
    		return 0;
    	}
    
    	cout<<"main is runing"<<endl;
    
    	cout<<"1 join err code is: "<<pthread_join(tid1, &rval1)<<endl;
    	cout<<"2 join err code is: "<<pthread_join(tid2, &rval2)<<endl;
    
    	cout<<"thread 1 return code is: "<<std::oct<<(int)(int *)rval1<<endl;
    	cout<<"thread 2 return code is: "<<std::oct<<(int)(int *)rval2<<endl;
    
    	cout<<"main is ended"<<endl;
    
    	return 0;
    
    }



    线程1连接正常,线程二由于分离后释放资源导致无法连接返回错误码22,return值也没有成功获取。


    线程取消

    取消函数原型

    int pthread_cancle(pthread_ttid)

    取消tid指定的线程,成功返回0。取消只是发送一个请求,并不意味着等待线程终止,而且发送成功也不意味着tid一定会终止

    用于取消一个线程,它通常需要被取消线程的配合。线程在很多时候会查看自己是否有取消请求。

    如果有就主动退出,这些查看是否有取消的地方称为取消点。

    取消状态,就是线程对取消信号的处理方式,忽略或者响应。线程创建时默认响应取消信号

     设置取消状态函数原型

    int pthread_setcancelstate(int state, int*oldstate) 

    设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,

     

    分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。

    取消类型,是线程对取消信号的响应方式,立即取消或者延时取消。线程创建时默认延时取消

    设置取消类型函数原型

    int pthread_setcanceltype(int type, int*oldtype)

    设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。

     

    取消一个线程,它通常需要被取消线程的配合。线程在很多时候会查看自己是否有取消请求

    如果有就主动退出,这些查看是否有取消的地方称为取消点

     

    很多地方都是包含取消点,包括

    pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()、write、read,大多数会阻塞的系统调用


    #include <stdio.h>
    #include <iostream>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    using namespace std;
    
    void *thread_fun(void *arg)
    {
    	int stateval;
    	int typeval=0;
    	//设置线程disable取消,此操作有点类似关中断,哈哈
    	stateval = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    	if(stateval != 0)
    	{
    		printf("set cancel state failed\n");
    	}
    
    	printf("Im new thread,wait 4s\n");//
    
    	sleep(4);//在等待的4s时间里主线程调用取消函数
    
    	printf("about to cancel \n");
    	//设置线程enable取消
    	stateval = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    	if(stateval != 0)
    	{
    		printf("set cancel state failed\n");
    	}
    	typeval = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    //	typeval = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    	if(typeval != 0)
    	{
    		printf("set cancel type failed\n");
    	}
    
    	printf("first cancel point\n");
    	printf("second cancel point\n");
    
    	return (void *)20;
    }
    
    int main()
    {
    	pthread_t tid ;
    	int err, cval, jval;
    	void *rval;
    
    	err = pthread_create(&tid, NULL, thread_fun, NULL);
    	if(err != 0)
    	{
    		printf("create thread failed\n");
    		return 0;
    	}
    	sleep(2);
    	printf("canceling new thread!\n");
    	cval = pthread_cancel(tid);//等待两秒取消子线程
    	if(cval != 0)
    	{
    		printf("cancel thread failed\n");
    	}
    	jval = pthread_join(tid, &rval);
    
    	printf("new thread exit code is %d\n", (int *)rval);
    
    	return 0;
    }



    展开全文
  • Linux线程-终止

    2012-11-12 20:17:08
    在前文讨论了线程创建的一些基本东西,这里讨论有哪些方法可以使线程终止线程终止又是如何与创建所需的参数进行关联的。 一,正常终止 线程在执行完成之后,正常终止。 二,线程取消 2.1 线程取消的定义 ...

    在前文讨论了线程创建的一些基本东西,这里讨论有哪些方法可以使线程终止,线程终止又是如何与创建所需的参数进行关联的。

    一,正常终止

    线程在执行完成之后,正常终止。

    二,线程取消

    2.1 线程取消的定义
    一般情况下,线程在其主体函数退出的时候会自动终止,但同时也可以因为接收到另一个线程发来的终止(取消)请求而强制终止。

    2.2 线程取消的语义
    线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略、或者立即终止、或者继续运行至Cancelation-point(取消点),由不同的Cancelation状态决定。线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点,也就是说设置一个CANCELED状态,线程继续运行,只有运行至Cancelation-point的时候才会退出。

    2.3 取消点
    根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用 pthread_testcancel(),从而达到POSIX标准所要求的目标,即如下代码段:

    pthread_testcancel();
    retcode = read(fd, buffer, length);
    pthread_testcancel();

    2.4 程序设计方面的考虑
    如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。

    2.5 与线程取消相关的pthread函数
    int pthread_cancel(pthread_t thread)
    发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。
    int pthread_setcancelstate(int state, int *oldstate)
    设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和 PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为 NULL则存入原来的Cancel状态以便恢复。
    int pthread_setcanceltype(int type, int *oldtype)
    设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和 PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
    void pthread_testcancel(void)
    检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。

    三,pthread_exit

    在线程内显示的调用,以终止线程。

    四,等待终止

    在一个线程里面,我们要等待另一个线程结束。可以通过调用pthread_join函数。

    pthread_join (pthread_t thread, void** threadreturn);

    这将会在调用线程引起阻塞,并且在创建thread所指定的线程时,其分离属性必须是pthread_create_joinable.否则调用出错。


    展开全文
  • 线程就有个执行流;一个进程至少有一个线程 2. 图解线程 PCB1所代表的进程通过vfork创建一个子进程,子进程再vfork一个新的子进程,以此类推产生两个新的子进程; 此时PCB1、PCB2、PCB3都指向同一块虚拟...

    更多linux知识点:linux目录索引

    1. 什么是线程

      线程是进程执行内部的一个执行分支,在一个进程内部运行的多种执行流;内部本质上是多个线程在同一个地址空间运行;第一个pcb称之为主线程;有多个线程就有多个执行流;一个进程至少有一个线程

    2. 图解线程

    1. PCB2所代表的进程通过vfork创建一个子进程,子进程再vfork一个新的子进程,以此类推产生两个新的子进程;

    2. 此时PCB1、PCB2、PCB3都指向同一块虚拟地址空间,通过操作把PCB1所指向的虚拟空间的资源(主要是数据和代码),分成3部分分别给PCB1、PCB2、PCB3

    3. 这些进程就被称为线程,这些线程之间满足互不干扰的条件,且这些线程共用同一虚拟空间,并且共用部分资源,在访问这些公共资源时,这些线程可以互相访问到对方的资源

    这里写图片描述

    3. linux下的线程

      linux下并没有真正意义上的线程存在,linux中使用进程来模拟实现线程,父进程创建子进程,子进程执行父进程的一部分代码,并且与父进程共享同一个地址空间。这些一个一个被创建出来的子进程可看到为线程,这种线程也称之为轻量级进程

    注:轻量级进程(LWP)是一种实现多任务的方法。与普通进程相比,LWP与其他进程共享所有(或大部分)它的逻辑地址空间和系统资源;linux下,CPU看到的所有进程都可以看作为轻量级进程

    4. 线程的资源(私有和共享)

    共享 私有
    数据段,代码段 每个线程都有自己的栈结构
    文件描述符表 上下文,(包含各种计数器的值、程序计数器和栈指针)
    每种信号的处理方式 线程id
    当前工作的目录 errno变量(当线程异常退出时的错误退出码)
    用户id和线程组id 信号屏蔽字
    调度优先级

    5. 线程的优缺点

    优点

    1. 线程占用的资源比进程少,只虚复制PCB即可
    2. 创建时代价较小
    3. 线程间的切换(调度)需要操作系统做的工作少很多
    4. 线程间共享数据更容易
    5. 在等待慢速 I/O操作结束的同时,程序可执行其他的计算任务。
    6. 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现。
    7. I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

    注:关于I/O密集型和计算密集型可参考这篇文章:CPU-bound(计算密集型) 和I/O bound(I/O密集型

    缺点

    1. 性能损失(一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享一个处理器。如果计算密集型线程的数量比可用的处理器多,那么就有可能造成较大的性能损失,这里的性能损失指的是操作系统增加了额外的同步和调度开销,而可用的资源不变);

    2. 健壮性降低(由于线程是共享同一块虚拟地址空间的,在运行期间,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,也就是说线程之间是缺乏保护的);

    3. 缺乏访问控制(当在线程中调用某些函数(OS函数,处理signal函数,调用kill/exit函数),可能会导致线程退出,从而使所有的线程都异常退出);

    4. 编程难度提高(线程共用同一块虚拟地址空间,势必在处理多线程时会有访问同一个资源等问题,此时就涉及到共享资源的处理)


    6. 线程控制

    6.0 写在前面

      在操作系统内部,它不管什么进程线程的,它只以PCB为准,只有在用户态里才有线程的概念。一般实现线程会用到一个POSIX线程库,在这里可以通过调用POSIX库里的函数来实现有关线程的各种操作。不过内核中也有一种内核级线程。

      两个基本类型:

    1. 用户级线程:管理过程全部由用户程序完成,操作系统内核心只对进程进行管理。如POSIX线程库。

    2. 系统级线程(核心级线程):由操作系统内核进行管理。操作系统内核给应用程序提供相应的系统调用和应用程序接口API,以使用户程序可以创建、执行、撤消线程。

    POSIX线程库

      由系统库支持。线程的创建和撤销以及线程状态的变化都由库函数控制并在目态(user态)完成,与线程相关的控制结构TCB保存在目态并由系统维护。由于线程对操作不可见(操作系统可见的必然保存在kernel态由系统维护),系统调度仍以进程为单位(同一进程内线程相互竞争),核心栈的个数与进程个数相对性。

    • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的

    • 要使用这些库函数,就要引入头文件

    • gcc在链接这些线程函数库时要使用编译器命令的“-lpthread”选项(pthread是共享库文件)

    6.1 创建线程

    注:创建出新线程后,新线程去执行函数,主线程继续往下运行,谁先谁后不一定,同理fork父子进程

            #include <pthread.h>
    
           int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                              void *(*start_routine) (void *), void *arg);
    
       //参数:
       //thread:线程id,将线程id存入,线程标识符,线程栈的起始地址,输出型参数
       //attr:线程属性,NULL,8种选项
       //函数指针:新线程执行该函数指针指向的代码,线程回调函数
       //arg:传递给函数指针指向的函数的参数,线程回调函数的参数
    
        //返回值:成功返回0,失败返回错误码,如:
        //EAGAIN   描述: 超出了系统限制,如创建的线程太多。 
        //EINVAL   描述: tattr 的值无效。

    例:

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    void* thread_func(void* arg)
    {
        (void)arg;
        while(1)
        {
            printf("I am new thread\n");
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
    
       if ( pthread_create(&tid,NULL,thread_func,NULL) == -1){
           perror("pthread_create");
           exit(1);
       }
    
       while(1){
           printf("I am  main thread\n");
           sleep(1);
       }
    
        return 0;
    }
    

    结果:

    这里写图片描述

    6.2 线程ID

      线程是进程的一个执行分支,并且线程在内核中的存在状态是轻量级进程,因此线程ID和进程ID存在一定的关系,可查看:linux下的线程ID和进程ID

    6.3 线程的查看以及多线程的调试

      线程是进程的执行分支,多个线程共享同一块虚拟地址空间,在这其中,多个线程共享数据段、 代码段等等,但还是存在自己私有的一些结构,对于这些结构,我们可以通过不同的方法可以进行查看。可参考:线程的查看以及多线程的调试

    6.4 等待线程——pthread_join

    1. 功能:以阻塞的方式回收新线程,可以得到线程的退出码,并回收其资源
    2. 如果不使用pthread_join回收线程,有可能造成和僵尸进程一样的问题,造成内存泄漏;
      #include <pthread.h>
      int pthread_join(pthread_t thread, //要等待的线程ID
      void **retval);//用于接收线程退出的退出码

    等待线程的目的:

    1. 保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出
    2. 回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间
    3. 获得新线程退出时的结果是否正确的退出返回值,这个有点类似回收僵尸进程的wait,保证不会发生内存泄露等问题
    6.5 终止线程

     方式1:在一个线程中return

      如果线程通过return返回,那么retval所指向的单元里存放的是tread函数的返回值

    例:main函数创建一个新线程,新线程执行完自己的函数,使用return退出,那么返回值就是退出码

    方式2:exit

      如果线程是自己调用exit终止的,那么就是直接退出,并且exit表示进程的退出

    exit和return的区别:

    1. return是函数的退出,exit是进程的退出

    2. return执行结束后会调用exit或和exit类似的函数,return会释放局部变量并且弹出栈桢,回到上一个函数继续执行

    方式3: 使用pthread_exit()

      线程自己调用函数终止,pthread_ jion()函数里的retval(退出码)就是pthread_exit的参数

    #include <pthread.h>
           void pthread_exit(void *retval);
    线程的退出函数,retval是退出码,该函数只是当前线程退出,不影响其他线程

    方式4:

      如果线程是通过pthread_ cancel被别的线程异常终止,则retval(退出码)就是PTHREAD_ CANCELED

    #include <pthread.h>
           int pthread_cancel(pthread_t thread);//线程ID
    //可以终止自己的线程也可以终止别人的线程
    //成功返回0,失败返回-1
    //终止自己算是成功退出,发回0,终止别的进程,则那个进程算是失败退出,返回-1;
    //不是立马执行,会延迟一会,等到cancel的时间点
    //系统调用的都是cancel点

    例1:使用return退出

    
    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    void* thread_func(void* arg)
    {
        (void)arg;
        int count = 0;
        while(1)
        {
            ++count;
            if(count > 10)
                return NULL;//使用return方式退出
            printf("I am new thread:%d,count: %d\n",pthread_self(),count);
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
    
       if ( pthread_create(&tid,NULL,thread_func,NULL) == -1){
           perror("pthread_create");
           exit(1);
       }
    
       while(1){
           printf("I am  main thread:%d\n",pthread_self());
           sleep(1);
       }
    
        return 0;
    }
    

    结果:

    这里写图片描述

    例2:exit退出

    
    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    void* thread_func(void* arg)
    {
        (void)arg;
        int count = 0;
        while(1)
        {
            ++count;
            if(count > 10)
                exit(1);//使用return方式退出
            printf("I am new thread:%d,count: %d\n",pthread_self(),count);
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
    
       if ( pthread_create(&tid,NULL,thread_func,NULL) == -1){
           perror("pthread_create");
           exit(1);
       }
    
       while(1){
           printf("I am  main thread:%d\n",pthread_self());
           sleep(1);
       }
    
        return 0;
    }
    

    结果:

    这里写图片描述

    例3:pthread_exit退出

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    void* thread_func(void* arg)
    {
        (void)arg;
        int count = 0;
        while(1)
        {
            ++count;
            if(count > 10)
                pthread_exit(NULL);
            printf("I am new thread:%d,count: %d\n",pthread_self(),count);
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
    
       if ( pthread_create(&tid,NULL,thread_func,NULL) == -1){
           perror("pthread_create");
           exit(1);
       }
    
       while(1){
           printf("I am  main thread:%d\n",pthread_self());
           sleep(1);
       }
    
        return 0;
    }
    

    结果:

    这里写图片描述

    例4:pthread_cancel

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <stdlib.h>
    #include <string.h>
    
    void* thread_func(void* arg)
    {
        (void)arg;
        while(1)
        {
            printf("I am new thread:%d\n",pthread_self());
            sleep(1);
        }
    }
    
    int main()
    {
        pthread_t tid;
    
       if ( pthread_create(&tid,NULL,thread_func,NULL) == -1){
           perror("pthread_create");
           exit(1);
       }
        int count = 0;
        void* ret;
       while(1){
           ++count;
    
           if(count > 5){
               pthread_cancel(tid);
               pthread_join(tid,&ret);
           }
           if(ret == PTHREAD_CANCELED)
                printf("thread is return,thread id: %d, return code:PTHREAD_CANCELED\n",tid);
            else
                printf("thread is return,thread id: %d, return code:NULL\n",tid);
    
    
           printf("I am main thread: %d,count: %d\n",pthread_self(),count);
           sleep(1);
       }
    
        return 0;
    }
    

    结果:

    这里写图片描述


    6.6 线程分离

       6.6.1 线程的两种状态——可结合、可分离
      
      线程分为两种状态:可结合态和分离态;默认情况下,线程被创建成可结合的。

    1. 可结合态:

    1. 这种状态下的线程是能够被其他进程回收其资源或杀死的,这句话我的理解是:与其说它能够被其他进程回收或杀死,不如说它需要被其他进程回收或杀死;当它在被其他线程回收之前,它的存储器资源(如栈)是不会释放的;
    2. 这跟子进程很相似,如果不用父进程wait回收的话,就会变成僵尸进程同理,如果一个可结合态线程不用pthread_join回收,则会变成类似僵尸进程

    2. 分离态

    1. 这种状态下的线程是不能够被其他线程回收或杀死的;它的存储资源在它终止时由系统自动释放
    2. 为了避免存储器泄漏,每个可结合线程需要显示的调用pthread_join回收;>要么就将其变成分离态的线程

      6.6.2 线程分离函数—–pthread_detach

        #include <pthread.h>
        int pthread_detach(pthread_t thread);
        //将pthread_thread对应的线程设为分离态的线程
    

    pthread_detach的两种用法:

    1. 新线程中写:pthread_detach(pthread_self());
    2. 主线程中写:pthread_detach(thread);

    注:多个线程,是在同一个进程中的,它们都共享着同一块虚拟空间,第一种方法是将自己从这些线程中分离出来;
    第二种方法是将指定的线程从这些线程中分离出去;简单来说就是,一个是自己把自己弄出去,一个是让别人把自己弄出去

    展开全文
  • Linux中有俩种方式可以使线程正常终止: 通过return从线程函数返回 通过调用pthread_exit()函数,使线程退出 另外线程受到其他线程的干扰或者自身出错,都会导致线程非正常终止,而这种终止是不可预见的。 无论...
  • Linux中pthread是我们进行多线程并发时经常使用的,pthread创建的子线程和主线程的终止顺序有什么样的关系,下面通过代码来总结下。 在代码测试前,先说下结论:  (1)主线程和子线程之间没有必然的退出次序关系...
  • Linux多线程编程

    2019-06-21 17:42:56
    作为多任务实现的一种机制,多线程应用得非常广泛,相对于多进程,多线程不仅运行效率高,而且还可以提高系统资源的使用效率。虽然网上关于多线程的讲解已经有一大堆,但出于学习的心态,有必要在这里做一下笔记。 ...
  • LINUX 多线程调试方法

    2019-12-26 11:12:39
    LINUX环境下的 多线程调试方法与总结 作为开发者的天堂,Linux为程序员提供了极其便利的方法和技巧,同时随着程序规模的增加,线程之间的绕来绕去,程序调试变得极其不稳定,因此,如何判断程序的问题出在哪里变得...
  • linux线程的取消(终止)

    2014-12-30 10:32:13
    关键: pthread_cancel函数发送终止信号 ...一般情况下,线程在其主体函数退出的时候会自动终止,但同时也可以因为接收到另一个线程发来的终止(取消)请求而强制终止。 2 线程取消的语义 线程取消
  • 1. 线程终止方式 一般来说,Posix的线程终止有两种情况:正常终止和非正常终止。线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;非正常终止是线程在其他线程的干预...
  • Linux多线程概述 了解如何正确运用线程是每一个优秀程序员必备的素质。线程类似于进程。如同进程,线程由内核按时间分片进行管理。在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同...
  • Linux 多线程编程线程分类线程按照其调度者可以分为用户级线程和内核级线程两种。内核级线程在一个系统上实现线程模型的方式有好几种,因内核和用户空间提供的支持而有一定程度的级别差异。最简单的模型是在内核为...
  • Linux 多线程编程   线程(Thread)已被许多操作系统所支持,包括Windows/NT ,Linux 以前的多线程其实是多进程,而现在意味着一个进程中有多个线程   使用多线程的原因(多线程的优点): 1.“节省”,启动...
  • linux多线程编程示例

    2017-10-12 15:18:22
    线程概念  线程是指运行中的程序的调度单位...一个进程可以有很多线程,每个线程并行执行不同的任务。 线程与进程比较  ① 和进程相比,它是一种非常“节俭”的多任务操作方式。在Linux系统中,启动一个新的进程必
  • 创建内核线程 1. 头文件 #include <linux/sched.h> //wake_up_process() #include <linux/kthread.h> //kthread_create()、kthread_run() #include <err.h> //IS_ERR()、PTR_ERR() 2. 实现 2.1创建线程 ...
  • 在使用pthread_cancel和pthread_join退出一个线程时,线程本身会立即停止运行代码并退出吗?如果在你试图退出一个线程时,该线程中还有未释放的资源,这时应该怎么处理呢? 在cancel一个线程时,线程体可能并不会...
  • Linux线程部分总结分为两部分:(1)线程的使用 ,(2)线程的同步与互斥。 第一部分线程的使用主要介绍,线程的概念,创建线程,线程退出,以及线程的终止与分离。第二部分主要介绍在多线程环境下,使用同步与互斥...
  • 很早以前就想写写linux多线程编程和windows下的多线程编程了,但是每当写时又不知道从哪个地方写起,怎样把自己知道的东西都写出来,下面我就谈谈linux多线程及线程同步,并将它和windows的多线程进行比较,看看...
  • Linux多线程详解

    2011-12-19 09:52:35
    线程也被称为轻权进程(lightweight process)。 在传统的UNIX上,一个进程让另一个实体做某个事务是用fork派生子进程的方法处理的。派生子进程的代价比线程要昂贵得多,尤其是在父子进程...Linux系统下的多线程遵循POS
  • Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别。不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断。本文中我们从 5 个方面总结出 Linux ...
1 2 3 4 5 ... 20
收藏数 56,988
精华内容 22,795
热门标签
关键字:

linux线程终止