线程的使用1

1. 创建一个线程

1.1 创建线程练习

线程实际上是应用层的概念,在 Linux 内核中,所有的调度实体都被称为任务 (task) ,

他们之间的区别是:有些任务自己拥有一套完整的资源,而有些任务彼此之间共享一套资源

线程的使用1_第1张图片

线程的使用1_第2张图片

线程的使用1_第3张图片

对此函数的使用需要知道以下几点:

1,线程例程指的是:如果线程创建成功,那么该线程会立即去执行的函数。

2,POSIX 线程库的所有 API 对返回值的处理原则都是一致的:成功返回 0,失败返回 错误码 errno。

3 ,线程属性如果为 NULL,则会创建一个标准属性的线程,线程的属性非常多,下面 是关于线程属性的详细讨论。

跟线程属性有关的 API 有:

线程的使用1_第4张图片

线程的使用1_第5张图片

thread1.c

#include 
#include 

//回调函数
void *xiancheng (void *argc)
{
    int i=0;
    while (1)
    {
        printf("%d\n",i);
        i++;
        sleep(1);
    }
    
}

int main()
{
    pthread_t tid;
    //创建一个线程
    pthread_create(&tid,NULL,&xiancheng,NULL);

    pause();//停留在此
    
}

成功

线程的使用1_第6张图片

1.2 退出线程

线程跟进程类似,在缺省的状态下退出之后,会变成僵尸线程,并且保留退出值。其他 线程可以通过相关 API 接合该线程——使其资源被系统回收,如果愿意的话还可以顺便获取 其退出值。下面是相关 API:

线程的使用1_第7张图片

1.3 接合指定线程

线程的使用1_第8张图片

用上述函数需要注意以下几点:

1,如果线程退出时没有退出值,那么 retval 可以指定为 NULL。

2,pthread_join( )指定的线程如果尚在运行,那么他将会阻塞等待。

3,pthread_tryjoin_np( )指定的线程如果尚在运行,那么他将会立即出错返回。

1.4 取消线程请求

另外,或许在某个时刻不能等某个线程“自然死亡”,而需要勒令其马上结束,此时可 以给线程发送一个取消请求,让其中断执行而退出。用到如下 API:

线程的使用1_第9张图片

而当线程收到一个取消请求时,他将会如何表现取决于两个东西:一是当前的取消状态, 二是当前的取消类型。线程的取消状态很简单——分别是 PTHREAD_CANCEL_ENABLE 和 PTHREAD_CANCEL_DISABLE,前者是缺省的,代表线程可以接受取消请求,后者代表关闭 取消请求,不对其响应。

而在线程接受取消请求的情况下,如何停下来又取决于两种不同的响应取消请求的策略 ——延时响应和立即响应,当采取延时策略时,线程并不会立即退出,而是要遇到所谓的“取 消点”之后,才退出。而“取消点”,指的是一系列指定的函数。

线程的使用1_第10张图片

1.5  分离线程的使用细节

以上API 都是针对线程属性操作的,所谓线程属性是类型为 pthread_attr_t 的变量, 设置一个线程的属性时,通过以上相关的函数接口,将需要的属性添加到该类型变量里 面,再通过 pthread_create( )的第二个参数来创建相应属性的线程。

线程属性变量的使用步骤是:

1,定义线程属性变量,并且使用 pthread_attr_init( )初始化。

2,使用 pthread_attr_setXXX( )来设置相关的属性。

3,使用该线程属性变量创建相应的线程。

4,使用 pthread_attr_destroy( )销毁该线程属性变量。

线程的属性很多,其中着重关注的几个属性 API 是:

一条线程如果是可接合的,意味着这条线程在退出时不会自动释放自身资源,而会成为 僵尸线程,同时意味着该线程的退出值可以被其他线程获取。因此,如果不需要某条线程的 退出值的话,那么最好将线程设置为分离状态,以保证该线程不会成为僵尸线程。

分离线程在退出时,相关资源会被系统自动回收,而不需要显式调用 pthread_join 函数等待线程结束。

重点

主线程的结束,会导致整个程序的退出结束,那时候任何线程的任何操作都将停止,包括其他线程要输出但是还没来得及输出的情况

线程的使用1_第11张图片

thread2.c

#include 
#include 

//分离线程的细节
//重点,主线程的结束,会导致整个程序的退出结束,那时候任何线程的任何操作都将停止,包括其他线程要输出但是还没来得及输出的情况

//回调函数
void *xiancheng (void *argc)
{
    int i=0;
    while (1)
    {
        sleep(1);
        printf("%d\n",i);
        i++;
        if(i>10){
            break;
        }

    }

    //终止线程的函数。它的作用是终止当前线程的执行,并将一个退出状态传递给主线程(或者调用 pthread_join 等待的线程)。
    //但是分离线程拿不到退出状态
    pthread_exit("byebye\n");
    
}

int main()
{
    printf("我创建线程啦\n");
    pthread_t tid1;
    pthread_t tid2;

    void* p1 = NULL;
    void* p2 = NULL;

    //设置分离属性
    //创建属性变量
    pthread_attr_t attr1;
    //初始化属性变量
    pthread_attr_init(&attr1);
    //对这个属性变量,设置分离属性
    pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_DETACHED);
    
	//把设置好的属性变量attr1,传到创建线程函数中
    //创建一个线程
    pthread_create(&tid1,&attr1,&xiancheng,NULL);//这个线程是分离属性的

    pthread_create(&tid2,NULL,&xiancheng,NULL);//默认创建的线程是可结合的属性

    pthread_join(tid1,&p1);//tid1是分离线程,主线程不需要等待它的执行
    pthread_join(tid2,&p2);//相当于wait,对于分分离线程它会一直等待子线程执行完成

    printf("p1:%s\n",(char*)p1);
    printf("p2:%s\n",(char*)p2); 
}

线程的使用1_第12张图片

2. 设置线程调度策略

2.1 nice函数

线程的使用1_第13张图片

动态优先级数值越大,优先级越低

nice.c

#include 
#include 
#include 
#include 
#include 

//nice函数


void *a1(void *arg)
{
	char *msg = (char *)arg;//把参数解出来,需要什么类型,按情况解参数

	while(1)
	{
		if(strcmp(msg,"A\0") == 0)
		{
			nice(-19);//给A的亲和度降到最低,cpu会打印他,因为亲和度低
		}
		if(strcmp(msg,"B\0") == 0)
		{
			nice(15);//给B的亲和度升到最高,cpu很少打印他,因为亲和度太高了
		}
		fprintf(stderr, "%c", *msg);
	}
	
}


//分离与接合
int main()
{
	//定义一个线程号tid
	pthread_t tid1;
	pthread_t tid2;
			

	pthread_create(&tid1, NULL, a1, "A");//屌丝线程,静态优先级为0
	
	pthread_create(&tid2, NULL, a1, "B");//屌丝线程,静态优先级为0
	
	pause();
	
}

线程的使用1_第14张图片

2.2 静态优先级和调度策略解析

2.2.1 获取、设置线程是否继承创建者的调度策略

线程的使用1_第15张图片

线程的使用1_第16张图片

2.2.2 获取、设置线程的调度策略

当需要给一个线程设置调度方面的属性时 ,必须先将线程的 inheritsched 设置为 PTHREAD_EXPLICIT_SCHED。

线程的使用1_第17张图片

SCHED _FIFO 调度策略为此,通俗讲就是,获得cpu就会一直执行自己直到自己运行结束,才会让出cpu

SCHED  RR 调度策略为此,通俗讲就是 ,每个线程都会获得cpu的时间在获得时间内执行,时间到了换下一个拥有时间的线程执行

前面两个策略有个条件,就是和同批次竞争者的静态优先级一样,如果有的竞争者静态优先级高过它,那就让这个静态优先级高的执行(老师说的高富帅)(就是如果他们的静态优先级一样的话来博弈。)

当线程的调度策略为 SCHED_OTHER 时,其静态优先级 (static priority) 必须设置 为 0 。该调度策略是 Linux 系统调度的默认策略,处于 0 优先级别的这些线程按照所谓的动 态优先级被调度,而动态优先级起始于线程的 nice 值,且每当一个线程已处于就绪态但被 调度器调度无视时,其动态优先级会自动增加一个单位,这样能保证这些线程竞争 CPU 的 公平性。

2.2.3 获取、设置线程静态优先级

线程的使用1_第18张图片

1,静态优先级是一个定义如下的结构体:

struct sched_param

{

int sched_priority;

};

set_policy.c
#include 
#include 
#include 
#include 
#include 


//静态优先级和调度策略的探讨

void *a1(void *arg)
{
	char *msg = (char *)arg;//把参数解出来,需要什么类型,按情况解参数

	
	while(1)
	{

		fprintf(stderr, "%c", *msg);
	}
	
}


//分离与接合
int main()
{
	//定义一个线程号tid
	pthread_t tid1;
	pthread_t tid2;
	
	pthread_attr_t attr1;
	pthread_attr_t attr2;
	
	
	//初始化属性变量
	pthread_attr_init(&attr1);
	pthread_attr_init(&attr2);
	
	//选择是否继承创建者的调度策略
	pthread_attr_setinheritsched(&attr1,PTHREAD_EXPLICIT_SCHED);
	
	pthread_attr_setinheritsched(&attr2,PTHREAD_EXPLICIT_SCHED);
	
	//设置线程的调度策略
	// pthread_attr_setschedpolicy(&attr1, SCHED_FIFO);  
	// pthread_attr_setschedpolicy(&attr2, SCHED_FIFO);

	pthread_attr_setschedpolicy(&attr1, SCHED_RR);  
	pthread_attr_setschedpolicy(&attr2, SCHED_RR);
	
	struct sched_param policy;
	
	policy.sched_priority = 20;
	
	//设置静态优先级
	pthread_attr_setschedparam(&attr1,&policy);//只有管理员才能修改线程的静态优先级
	
	// policy.sched_priority = 21;

	pthread_attr_setschedparam(&attr2,&policy);
	

	pthread_create(&tid1, &attr1, a1, "A");//屌丝线程,静态优先级为0
	pthread_create(&tid2, &attr2, a1, "B");//屌丝线程,静态优先级为0
	
	pause();
	
}

你可能感兴趣的:(进程线程,linux,c语言,信号处理)