线程控制与线程分离

一、线程控制

1、线程概念:

线程是资源调度的基本单位,线程是进程内部的一个执行流,在进程的地址空间内运行。Linux 下没有真正意义上的线程,线程是用进程模拟的,又被称为轻量级进程。

2、线程资源:

一个程序中的多个线程共享同一地址空间,因此代码段,数据段内容是共享的。

除此之外,以下内容也是共享的:

1. 文件描述符表
2. 每种信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)
3. 当前工作目录
4. 用户id和组id

 

但有些资源是每个线程各有一份的:

1. 线程id

2.上下文,包括各种寄存器的值、程序计数器和栈指针
3. 栈空间
4. errno变量
5. 信号屏蔽字
6. 调度优先级

3、线程创建:

(1)创建函数: int pthread_create(pthread_t*thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
(2)获取线程id:  pthread_tpthread_self(void);

创建函数说明:

创建成功:返回0 ;创建失败:返回错误码,可将错误码通过strerror()转换为字符串描述。 

参数1:线程id地址(只在用户区有效)。 &id

参数2:线程属性,一般设置为NULL(非分离方式)。 

参数3:函数指针,指向线程函数。 (线程函数名)

参数4:线程函数的参数。(一般为NULL

 

4、终线程

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

       1. 从线程函数return。这种法对主线程不适用,从main函数return相当于调exit//线程return

       2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程,用pthread_cancel⽌⼀个线程分同步和异步两种情况。//被动终止

       3. 线程可以调用pthread_exit终止自己。//自己终止

5、线程等待

 int pthread_join(pthread_t thread, void **retval);

调用该函数等待的线程将挂起等待,直到id为thread的线程终止。线程以不同方式终止,pthread_join得到的结果是不同的。具体如下:

1.如果thread线程通过return返回,value_ptr所指向的单元⾥里存放的是thread线程函数的返回值。

2.如果thread线程被别的线程调⽤用pthread_cancel异常终掉,value_ptr所指向的单元⾥里存放的是常数PTHREAD_CANCELED。

3.如果thread线程是⾃自⼰己调⽤用pthread_exit终⽌止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。

注:对于线程进行join之后线程的状态将是detach状态(分离),同样的pthread_cancel函数可以对线程进行分离处理。所以,不能同时对一个线程进行join和detach操作

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

void* thread1(void* arg)
{

printf("new thread1\n");
    return (void*)123;
}

void* thread2(void* arg)
{

    while(1)
    {

    printf("newthread2\n");
        sleep(1);
        pthread_exit((void*)456);
    }

}

void* thread3(void* arg)//被其他线程cancel
{

while(1)
    {

    printf("newthread3\n");
        sleep(1);
    }

return NULL;
}

int main()
{

pthread_t tid1,tid2,tid3,tid4;
    void* val = NULL;
    pthread_create(&tid1,NULL,thread1,NULL);
    pthread_create(&tid2,NULL,thread2,NULL);
    pthread_create(&tid3,NULL,thread3,NULL);
    pthread_create(&tid4,NULL,thread4,NULL);
    

pthread_join(tid1,&val);
    printf("thread1 is quit,thread1 id is %lu, exitcode:%d\n",tid1,(int)val);
    pthread_join(tid2,&val);
    printf("thread2 is quit,thread2 id is %lu, exitcode:%d\n",tid2,(int)val);

pthread_cancel(tid3);
    pthread_join(tid3,&val);
    printf("thread3 is quit,thread3 id is %lu, exitcode:%d\n",tid3,(int)val);

    return 0;

 

运行结果:

 

注:

可见在Linux的pthread库中常数PTHREAD_CANCELED的值是-1。可以在头⽂文件pthread.h中找到它的定义。

一般情况下,线程终止后,其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。 但是线程也可以被置为detach 状态,这样的线程一旦终止就⽴立刻回收它占用的所有资源,而不保留终⽌止状态。不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL。 对一个尚未detach的线程调用pthread_join或pthread_detach都可以把该线程置为detach状态,也就是说,不能对同一线程调用两次pthread_join,或者如果已经对⼀一个线程调用了pthread_detach就不能再调用pthread_join了

 

二、分离线程

在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。在被其他线程回收之前,它的存储器资源(例如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀死的,它的存储器资源在它终止时由系统自动释放。

1、默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程结束后资源都要被回收,要么调用pthread_join;要么调用pthread_detach函数被分离。如果一个可结合线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。

2 由于调pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。例如,在Web服务器中当主线程为每个新来的连接请求创建一个子线程进行处理的时候,主线程并不希望因为调用pthread_join而阻塞(因为还要继续处理之后到来的连接请求),这时可以在子线程中加入代码 pthread_detach(pthread_self())

或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)将该子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。


注意:

如果设置一个线程为分离线程,而这个线程运行又非常快,它很可能在pthread_create函数返回之前就终止了,它终止以后就可能将线程号和系统资源移交给其他的线程使用,这样调用pthread_create的线程就得到了错误的线程号。要避免这种情况可以采取一定的同步措施,最简单的方法之一是可以在被创建的线程里调用pthread_cond_timewait函数,让这个线程等待一会儿,留出足够的时间让函数pthread_create返回。设置一段等待时间,是在多线程编程里常用的方法。但是注意不要使用诸如wait()之类的函数,它们是使整个进程睡眠,并不能解决线程同步的问题。

在默认情况下线程是非分离状态的,这种情况下,主线程等待被创建的线程结束。只有当pthread_join()函数返回时,被创建的线程才算终止,才能释放自己占用的系统资源。

 

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

void* thread(void *_arg)
{

//pthread_detach(pthread_self());//线程自已设置自已的可分离属性
printf("new thread is run...\n");
    return (void*)1;
}

int main()
{

pthread_t tid;
    int ret = pthread_create(&tid,NULL,thread,NULL);
    if(ret != 0)
    {       

printf("threadcreate failed,error code:%s\n",strerror(ret));
return ret;
    }

sleep(1);

pthread_detach(tid);//将子线程属性设置为分离(非阻塞,可立即返回)

 void* val = NULL;
    if((pthread_join(tid, &val) != 0))
    {

       printf("thread wait failed\n");
ret = 1;

}  

else

{

       printf("thread id : %u ,exit code : %d\n",tid,(int)val);
ret = 0; 

}

return ret;

}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值