多线程基础编程——创建,获取,终止,结束,清理

线程的简单概述

线程也叫做轻量进程(Lightweight Process,LWP),是程序执行流的最小单元。

   1.根据上面这幅图,说明一个进程的所有信息对于该进程中的线程都是共享的,包括可执行程序的代码,程序的全剧内存和堆内存,栈以及文件描述符。同时线程也包含一些私有信息。

线程标识

进程有进程ID,线程一样也有自己的ID。但是线程id只有在他所属的进程上下文中才有意义。线程ID是用pthread_t数据类型来表示的,(实现时:pthread_t是一个结构体类型)

函数1: 

#include<pthread.h>

int pthread_equal(pthread_t tidl1, pthread_t tid2);  //相等返回非0值,不相等返回0;

因为pthread_t类型为结构体,所以我们不能用一种可移植的方式进行打印,打印线程ID是非常有必要的

函数2:

#include<pthread.h>

pthread_t pthread_self(void);//获取线程自身ID,返回调用线程的线程ID。

线程的创建

  进程当中如何新增线程?

函数3:

int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict attr,void *(*start_rtn)(void*),void *restrict arg);

//成功返回0,错误返回错误编号。

当pthread_create创建线程成功时,新创建的线程的ID会被设置成tidp所指向的内存单元。attr用于制定各种不同的线程属性(默认属性为NULL),新创建的线程start——rtn函数开始运行:如果需要向start_rtn中传递的参数有一个以上,那需要将这些参数放在一个结构中,然后将这个结构的地址作为arg参数传入。

示例1:如何创建线程,以及打印线程ID?

#include"../../xuexi/shell/apue.h"
#include<pthread.h>
pthread_t ntid;//全局的用于接受线程创建成功获取的信息
void printids(const char* s)
{
		pid_t pid;
		pthread_t tid;

		pid = getpid();
		tid = pthread_self();

		printf("%s pid %lu tid %lu (0x%lx)\n)",s,(unsigned long)pid,(unsigned long)tid,(unsigned long)tid);
}
void* thr_fn()
{
		printids("new pthread:");
		return 0;
}
int main()
{
		int err;//用于接受线程创建的返回值
		err = pthread_create(&ntid,NULL,thr_fn,NULL);

		if(err!=0)
		{
				err_exit(err,"can not creat pthread:");
		}
		printids("main pthread:");
		sleep(1);
		return 0;
}

线程终止

  单线程可以通过三种方式退出,是在不终止整个进程的前提下,停止他的控制流。

1.线程可以简单得从启动例程中返回,返回值是线程的退出码。

2.线程可以被同一进程中的线程取消。

3.线程调用pthread_exit。

函数4:

#include<pthread.h>

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

调用线程将一直阻塞,知道指定的线程调用pthread_exit,从启动例程中返回或者被取消。

如果我们对线程的返回值不感兴趣,那么可以将RVAL_PTR设置为NULL,这样调用该函数可以等待指定的线程的终止,但不获取线程的终止状态。

例2:如何获取已终止线程的退出码?

#include"../../xuexi/shell/apue.h"
//如何获取已经终止的线程的推出码
//使用了pthread_join函数
#include<pthread.h>

void* thr_fn1(void* arg)
{
		printf("thread1 returning\n");
		return ((void*)1);
}
void* thr_fn2(void* arg)
{
		printf("thread2 exiting\n");
		pthread_exit((void*)2);
}
int main()
{
		pthread_t tid1,tid2;
		void* tret;
		int err = pthread_create(&tid1,NULL,thr_fn1,NULL);
		if(err != 0)
				printf("can not create thread 1");
		err = pthread_create(&tid2,NULL,thr_fn2,NULL);
		if(err != 0)
				printf("can not create thread 2");

		err = pthread_join(tid1,&tret);
		if(err != 0)
				printf("can not join with thread1");
		printf("thread 1 exit code %ld\n",(long)tret);
		err = pthread_join(tid2,&tret);
		if(err != 0)
				printf("can not join with thread2");
		printf("thread 2 exit code %ld\n",(long)tret);
		exit(0);

}

函数5:

#include<pthread.h>

int pthread_cancel(pthread_t tid);

注意这只是提出的请求,同时呢,被提出请求的线程还可以选择忽略取消或者控制如何被取消。

函数6:

#include<pthread.h>

void pthread_cleanup_push(void (*rtn)(void*),void *arg);
void pthread_cleanup_pop(int execute);

线程清理处理函数。处理程序记录在栈中,也就是说,它们的执行顺序与注册时相反。

当线程执行以下动作时,清理函数rtn是由pthread_cleanup_push函数调度的,调用时只有一个参数arg:

:调用pthread_exit时;

:响应取消请求时;

:用非零execute参数调用pthread_cleanup_pop时。

if execute参数设置为0,那么不调用清理函数。

猜你喜欢

转载自blog.csdn.net/genzld/article/details/83626455
今日推荐