线程 属性、取消线程、多线程

12.6 线程的属性:
    线程创建后,在程序退出之前我们可以通过pthread_join再次与线程同步,在结束的时候向主线程返回一些数据。有时候我们不需要线程结束的时候向主线程返回数据,也不需要主线程等待他的结束,这一类型的线程叫做脱离线程。可以通过修改线程的属性或者pthread_deatch的方法来创建它们。
    线程属性最重要的函数就是pthread_attr_init,它的作用是初始化一个线程属性对象。
#include  <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
    与前面一样,该函数成功时返回0,失败时返回错误代码。
    还有一个回收函数pthread_attr_destory,它的目的是对属性对象进行清理和回收,一旦对象回收 了,除非重新被初始化,否者不能再使用。
    初始化一个线程对象后,我们就可以调用其他的函数来设置不同的属性行为。主要的函数如下:

 1 #include<pthread.h>
 2 int pthread_attr_setdetachstate(pthread_attr_t* attr,int detachstate);
 3 int pthread_attr_getdetachstate(const pthread_attr_t* attr,int detachstate);
 4 int pthread_attr_setschedpolicy(pthread_attr_t*attr,int policy);
 5 int pthread_attr_getschegpolicy(const pthread_attr_t* attr,int policy);
 6 int pthread_attr_setschedparam(pthread_attr_t* attr,struct sched_param* param);
 7 int pthread_attr_getschedparam(const pthread_attr_t* attr,struct sched_param* param);
 8 int pthread_attr_setinheritsched(pthead_attr_t* attr, int inherit);
 9 int pthread_attr_getinheritsched(const pthread_attr_t* attr,int* inhert);
10 int pthread_attr_setscope(pthread_attr_t* attr,int scope);
11 int pthread_attr_getscope(const pthread_attr_t* attr ,int * scope);
12 int pthread_attr_setstacksize(pthread_attr_t* attr,int scope);
13 int pthread_attr_getstacksize(const pthread_attr_t* attr,int* scope);


    可见线程可以使用的属性很多,但是通常不需要设置太多的属性就可以正常工作。
       ❑ detachedstate:这个属性允许我们无需对线程进行重新合并。与大多数_set类函数一样,它以一个属性指针和一个标志为参数来确定需要的状态。pthread_attr_setdetachstate函数可能用到的两个标志分别是PTHREAD_CREATE_JOINABLE和PTHREAD_CREATE_DETACHED。这个属性的默认标志值是PTHREAD_CREATE_JOINABLE,所以可以允许两个线程重新合并。如果标志设置为PTHREAD_CREATE_DETACHED,就不能调用pthread_join来获得另一个线程的退出状态。
      ❑ schedpolicy:这个属性控制线程的调度方式。它的取值可以是SCHED_OTHER、SCHED_RP和SCHED_FIFO。这个属性的默认值为SCHED_OTHER。另外两种调度方式只能用于以超级用户权限运行的进程,因为它们都具备实时调度的功能,但在行为上略有区别。SCHED_RP使用循环(round-robin)调度机制,而SCHED_FIFO使用“先进先出”策略。
      ❑ schedparam:这个属性是和schedpolicy属性结合使用的,它可以对以SCHED_OTHER策略运行的线程的调度进行控制。
      ❑ inheritsched:这个属性可取两个值:PTHREAD_EXPLICIT_SCHED和PTHREAD_INHERIT_SCHED。它的默认取值是PTHREAD_EXPLICIT_SCHED,表示调度由属性明确地设置。如果把它设置为PTHREAD_INHERIT_SCHED,新线程将沿用其创建者所使用的参数。
      ❑ scope:这个属性控制一个线程调度的计算方式。
        ❑ stacksize:这个属性控制线程创建的栈大小,单位为字节。它属于POSIX规范中的“可选”部分,只有在定义了宏_POSIX_THREAD_ATTR_STACKSIZE的实现版本中才支持。Linux在实现线程时,默认使用的栈很大,所以这个功能对Linux来说显得有些多余。
      实验:脱离线程
//创建脱离线程,

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void* thread_function(void* arg);
char message[]={"Hello thread!"};
int thread_finished=0;
​
int main()
{
    pthread_t a_thread;
    int res;
    pthread_attr_t pattr;
    //初始化属性
    res=pthread_attr_init(&pattr);
    if(res!=0)
    {
        perror("Init threadattr failed");
        exit(EXIT_FAILURE);
    }
    //设置属性
    res=pthread_attr_setdetachstate(&pattr,PTHREAD_CREATE_DETACHED);
    if(res!=0)
    {
        perror("Setting attr failed");
        exit(EXIT_FAILURE);
    }
    //创建线程
    res=pthread_create(&a_thread,&pattr,thread_function,(void*)message);
    if(res!=0)
    {
        perror("Create thread failed");
        exit(EXIT_FAILURE);
    }
    //属性使用完毕后释放资源
    (void)pthread_attr_destroy(&pattr);
    //循环,等待新线程设置结束标准;这里表明主线程和其他线程共享全局变量。
    
    while(thread_finished!=1)
    {
        printf("Wating for thread finished\n");
        sleep(1);
    }
    printf("other thread finished\n");
    exit(EXIT_SUCCESS);
    return 0;
}
​
void* thread_function(void*arg)
{
    printf("Thread is running.\nArgument is :%s\n",(char*)arg);
    sleep(1);
    printf("Second thread setting finished flag,and exiting now\n");
    thread_finished=1;
    pthread_exit(NULL);
}


线程属性:调度
    另外一个可能需要修改的属性:调度。改变调度属性和设置脱离状态非常类似,可以使用sched_get_priority_max和sched_get_priority_min这两个属性来差早可用的优先级别。
    实验:调度

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>void* thread_function(void* arg);
char message[]={"Hello thread!"};
int thread_finished=0;
int main()
{
    int max_policy;
    int min_policy;
    struct sched_param sched_value;
    pthread_t a_thread;
    int res;
    pthread_attr_t pattr;
    //初始化属性
    res=pthread_attr_init(&pattr);
    if(res!=0)
    {
        perror("Init threadattr failed");
        exit(EXIT_FAILURE);
    }
    //设置脱离属性
    res=pthread_attr_setdetachstate(&pattr,PTHREAD_CREATE_DETACHED);
    if(res!=0)
    {
        perror("Setting attr failed");
        exit(EXIT_FAILURE);
    }
    //设置调度策略
    res=pthread_attr_setschedpolicy(&pattr,SCHED_OTHER);
    if(res!=0)
    {
        perror("Set sched failed");
        exit(EXIT_FAILURE);
    }
    //查找可使用的优先级
    max_policy=sched_get_priority_max(SCHED_OTHER);
    min_policy=sched_get_priority_min(SCHED_OTHER);
    //设置优先级
    sched_value.sched_priority=min_policy;
    res=pthread_attr_setschedparam(&pattr,&sched_value);
    if(res!=0)
    {
        perror("Set sched attr failed");
        exit(EXIT_FAILURE);
    }
    //创建线程
    res=pthread_create(&a_thread,&pattr,thread_function,(void*)message);
    if(res!=0)
    {
        perror("Create thread failed");
        exit(EXIT_FAILURE);
    }
    (void)pthread_attr_destroy(&pattr);
    //循环,等待新线程设置结束标准;这里表明主线程和其他线程共享全局变量。
    
    while(thread_finished!=1)
    {
        printf("Wating for thread finished\n");
        sleep(1);
    }
    printf("other thread finished\n");
    exit(EXIT_SUCCESS);
    return 0;
}
void* thread_function(void*arg)
{
    printf("Thread is running.\nArgument is :%s\n",(char*)arg);
    sleep(4);
    printf("Second thread setting finished flag,and exiting now\n");
    thread_finished=1;
    pthread_exit(NULL);
}


7、取消一个线程:
    请求终止的函数:
    int pthread_cancle(pthread_t thread);提供一个进程标识符,就可以终止它,在主线程是如此简单,但是在被取消的线程是就不是这么简单了!!
    线程可以使用pthread_setcanclestate设置自己的取消状态:
    int pthread_setcanclestate(int state,int*oldstate);
    第一个参数可以是PTHREAD_CANCLE_ENABLE这个值允许取消请求,PTHREAD_CANCLE_DISABLE,它的作用是忽略取消请求。oldstate指针用于获取先前的状态,没有必要的时候可以设置为NULL; 如果取消请求被接受了,线程就可以进入第二个控制层次,用pthread_setcanceltype设置取消类型。
    int pthread_setcancletype(int type,int* oldtype);
    type参数可以有两种取值:一个是PTHREAD_CANCEL_ASYNCHRONOUS(立即取消),它将使得在接收到取消请求后立即采取行动;另一个是PTHREAD_CANCEL_DEFERRED(延迟取消),它将使得在接收到取消请求后,一直等待直到线程执行了下述函数之一后才采取行动。具体是函数pthread_join、pthread_cond_wait、pthread_cond_timedwait、pthread_testcancel、sem_wait或sigwait。
    实验:取消一个线程

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>char message[]={"Hello thread!"};
void* thread_function(void*arg)
{
   int i,res;
   res=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);//在新创建的线程中,我们首先将取消状态设置为允许取消,
   if(res!=0)
   {
       perror("set cacle state failed");
       exit(EXIT_FAILURE);
   }
  res=pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);//然后将取消类型设置为延迟取消
  //res=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
   if(res!=0)
   {
       perror("set cancle type error");
       exit(EXIT_FAILURE);
   }
   printf("Thread_Function is runing\n");
    //最后,线程在循环中等待被取消
   for(i=0;i<10;i++)
   {
       printf("Thread is still runing\n");
       sleep(1);
   }
   pthread_exit(NULL);
}
​
int main()
{
    pthread_t a_thread;
    int res;
    void* thread_res;
    int i;
    //创建线程
    //以通常的方法创建了新线程后,主线程休眠一会儿(好让新线程有时间开始执行),然后发送一个取消请求。
    res=pthread_create(&a_thread,NULL,thread_function,NULL);
    if(res!=0)
    {
        perror("Create thread error");
        exit(EXIT_FAILURE);
    }
    sleep(3);
    printf("Canceling thread \n");
    res=pthread_cancel(a_thread);
    if(res!=0)
    {
        perror("cancel a thread failed");
        exit(EXIT_FAILURE);
    }
    printf("wating for thread to finish\n");
    if(res!=0)
    {
        perror("thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}


多线程:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void* thread_function(void* arg)
{
     int my_number;
     int Rand;
    // my_number=(int)arg;
     my_number=*(int*)arg;
     printf("Thread_function runing from %d\n",my_number);
     Rand=1+(int)(9.0*rand()/(RAND_MAX+1.0));
​
     sleep(Rand);//休眠一个随机时间
     printf("Bye from %d\n",my_number);
     pthread_exit(NULL);  
}
int main()
{
    int res;
    pthread_t thread_id[6];
    void * thread_res;
    int num_of_thread;
    for(num_of_thread=0;num_of_thread<6;num_of_thread++)
    {
        //res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)num_of_thread);
        res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)&num_of_thread);
        if(res==0)
        {
            sleep(1);
        }
        else
        {
            perror("Create thread fauiled");
            exit(EXIT_FAILURE);
        }
    }
    for(num_of_thread=5;num_of_thread>=0;num_of_thread--)
    {
        res=pthread_join(thread_id[num_of_thread],&thread_res);
        if(res==0)
        {
            printf("Picked ip a thread \n");
        }
        else
        {
            perror("Picedf up failed");
            exit(EXIT_FAILURE);
        }
    }
    printf("Picede upo all\n");
    printf("Done\n");
    exit(EXIT_SUCCESS);
}


       我们创建了许多线程并让它们以随意的顺序结束执行。这个程序有一个小漏洞,如果将sleep调用从启动线程的循环中删除,它就会变得很明显。
        改进:

扫描二维码关注公众号,回复: 1027338 查看本文章
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <unistd.h>
 5 #include <pthread.h>
 6  7 void* thread_function(void* arg)
 8 {
 9      int my_number;
10      int Rand;
11      my_number=(int)arg;
12      printf("Thread_function runing from %d\n",my_number);
13      Rand=1+(int)(9.0*rand()/(RAND_MAX+1.0));
14 15      sleep(Rand);//休眠一个随机时间
16      printf("Bye from %d\n",my_number);
17      pthread_exit(NULL);  
18 }
19 int main()
20 {
21     int res;
22     pthread_t thread_id[6];
23     void * thread_res;
24     int num_of_thread;
25     for(num_of_thread=0;num_of_thread<6;num_of_thread++)
26     {
27         res=pthread_create(&thread_id[num_of_thread],NULL,thread_function,(void*)num_of_thread);
28         if(res!=0)
29         {
30             perror("Create thread fauiled");
31             exit(EXIT_FAILURE);
32         }
33     }
34     for(num_of_thread=5;num_of_thread>=0;num_of_thread--)
35     {
36         res=pthread_join(thread_id[num_of_thread],&thread_res);
37         if(res==0)
38         {
39             printf("Picked ip a thread \n");
40         }
41         else
42         {
43             perror("Picedf up failed");
44             exit(EXIT_FAILURE);
45         }
46     }
47     printf("Picede upo all\n");
48     printf("Done\n");
49     exit(EXIT_SUCCESS);
50 }



猜你喜欢

转载自www.cnblogs.com/Hello-LiuLiu/p/9090019.html