您的位置:首页 > 其它

线程的创建、等待、终止、分离

2017-07-31 17:47 302 查看
在linux的下线程是在进程的地址空间中运行的是进程内部的一个执行分支,被称为轻量级进程。线程的原理如下图:      


如图所示上图中的所有线程都是和主线程公用同以空间通过页表映射到同一物理内存。

由于同一进程的多个线程共享同一地址空间,因此文本段和数据段都是共享的,如果定一个函数,在各个线程都可调用,如果定义一个全局变量,在各个线程中都可以访问到,除此之外,各线程共享一下进程资源和环境。

1、文件描述符表。

2、每个信号的处理方式(SIG_IGN、SIG_DFL或者自定义的信号处理函数)。

3、当前工作目录。

4、用户ID和组ID。

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

1、线程ID

2、上下文,包括各种寄存器的值、程序计数器和栈指针。(非常重要)

3、栈空间

4、errno变量

5、信号屏蔽字。

6、调度优先级。

线程与进程的区别归纳:

a.地址空间和其它资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

b.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段

的辅助,以保证数据的一致性。

c.调度和切换:线程上下文切换比进程上下文切换要快得多。

d.在多线程OS中,进程不是一个可执行的实体。

线程的创建

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,  void *(*start_routine) (void *), void *arg);
第一个参数为指向线程标识符的指针。

第二个参数用来设置线程属性。

第三个参数是线程运行函数的起始地址。

最后一个参数是运行函数的参数。

返回值:成功返回0,失败返回错误号。以前学过的系统函数都是成功返回0,失败返回-1,而错误号保存在全局变

errno中,而pthread库的函数都是通过返回值返回错误号,虽然每个线程也都有一个errno,但这是为了兼容其它函数接口

而提的,pthread库本身并不使用它,通过返回值返回错误码更加清晰。

注意事项

因为pthread并非Linux系统的默认库,而是POSIX线程库。在Linux中将其作为一个库来使用,因此加上 -lpthread

(或-pthread)以显式链接该库。函数在执行错误时的错误信息将作为返回值返回,并不修改系统全局变量errno

当然也无法使用perror()打印错误信息。

线程创建的源代码

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

void* thread_run(void *_val)
{
printf("%s: pid is %d, tid is %s : %u\n", (char*)_val, (int)getpid()\
,(unsigned long long)pthread_self());
return NULL;
}

int main()
{
pthread_t tid;
int err = pthread_create(&tid, NULL, thread_run, "other thread run");
if(err != 0)
{
printf("create thread error!: info is %s\n", strerror(err));
}
printf("main thread run : pid is %d, tid is %s : %u\n", (int)getpid()\
,(unsigned long long)pthread_self());
sleep(1);
return 0;
}




从上图可以看出来线程和主线程的pid是都是3264,说明他们是同一进程下的不同线程。

线程的等待

int pthread_join(pthread_t thread, void **retval);
参数 :

thread: 线程标识符,即线程ID,标识唯一线程。

retval: 用户定义的指针,用来存储被等待线程的返回值。

线程的终止

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

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

2. 一个线程可以调用pthread_cancel终止同一进程中的另一个线程。

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

线程的等待和终止源代码

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

void* thread1(void* _val)
{
printf("thread 1 returning ...\n");
return (void*)1;
}
void* thread2(void* _val)
{
printf("thread 2 exiting....\n");
pthread_exit((void*)2);
}
void* thread3(void* _val)
{
while(1)
{
printf("pthread 3 is runninng, wait for be cancal..\n");
sleep(1);
}
return NULL;
}

int main()
{
pthread_t tid;
void* tret;
//pthread 1 return
pthread_create(&tid, NULL, thread1, NULL);
pthread_join(tid, &tret);
printf("thread return, thread id is : %u, return code is: %d\n",\
(unsigned long long)tid, (int)tret);
//pthread 2 exit
pthread_create(&tid, NULL, thread2, NULL);
pthread_join(tid, &tret);
printf("thread return, thread id is : %u, return code is: %d\n",\
(unsigned long long)tid, (int)tret);
//pthread 3 cancel by other
pthread_create(&tid, NULL, thread3, NULL);
sleep(3);
pthread_cancel(tid);
pthread_join(tid, &tret);
printf("thread return, thread id is : %u, return code is: %d\n",\
(unsigned long long)tid, (int)tret);
return 0;
}



线程分离

线程是可结合的(joinable)或者是分离的(detached)。一个可结合的线程能够被其他线程收回其资源和杀死。在

被其他线程回收之前,它的存储器资源(例如栈)是不释放的。相反,一个分离的线程是不能被其他线程回收或杀

死的,它的存储器资源在它终止时由系统自动释放。

默认情况下,线程被创建成可结合的。为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用

pthread_join;要么通过调用pthread_detach函数被分离。

如果一个可结合线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process,即还有一部分资源没有被

回收,所以创建线程者应该调用pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源。

由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。例如,在

Web服务器中当主线程为每个新来的连接请求创建一个子线程进行处理的时候,主线程并不希望因为调用

pthread_join而阻塞(因为还要继续处理之后到来的连接请求),这时可以在子线程中加入代码

pthread_detach(pthread_self())或者父线程调用pthread_detach(thread_id)(非阻塞,可立即返回)这将该子线程的

状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。

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

void* hardler(void* _val)
{
pthread_detach(pthread_self());
printf("%s\n", (char*)_val);
return NULL;
}

int main()
{
pthread_t tid;
int tret = pthread_create(&tid, NULL, hardler, " thread_run...");
//pthread_detach(tid);

a86b
if(tret != 0)
{
printf("create thread error!, info is : %s\n", strerror(tret));
}

//wait
int ret = 0;
sleep(1);
if(0 == pthread_join(tid, NULL))
{
printf("pthread wait success!\n");
}
else
{
printf("pthread wait failed\n");
ret = 1;
}
return 0;
}




这里我们让子线程先分离在退出然后让主线程等待回收资源这时候,不能回收其资源,因为已经被操作系统回收
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: