POSIX多线程程序设计学习篇之五(线程高级编程)

一,一次性初始化

pthread_once_t once_control = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t *once_control,void(*init_routine)(void));

参数1: 控制变量
参数2: 初始化函数,这个函数由作者完成,内容为你需要初始化的语句。
返回值:
若成功返回0,若失败返回错误编号。
注意:
(1) once_control必须先使用PTHREAD_ONCE_INIT宏静态地初始化然后才能调用pthread_once函数。
(2) pthread_once函数可以在多处调用,或者调用多次,但是只执行一次,
    pthread_once函数首先检查控制变量,判断是否已经完成初始化,如果完成就直接return;
    否则,pthread_once调用初始化函数。
(3) 某个线程初始化时,另外的线程调用pthread_once,则调用线程等待,直到那个线程完成初始化。

举例如下在线程私有数据举例中有,请参考。


二,线程私有数据

1,key的创建与销毁

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
参数1:为指向一个键值的指针,
参数2:为一个如同C++中的析构函数,当每个线程结束时,系统将调用这个函数来释放绑定在这个键上的内存块。
int pthread_key_delete(pthread_key_t key);

2,key与私有数据指针的绑定
int pthread_setspecific(pthread_key_t key,const void *pointer));//将指针与key绑定
void* pthread_getspecific(pthread_key_t key);//通过key获得对应地址。


注意点:
(1)虽然是同一个key,但是在不同的线程里不会冲突,设置同样的key,得到的指针是分别与各自线程对应的指针。
(2)作用在于每个线程可以定义各自的私有数据,而且只能通过key得到地址,每个线程只能通过key得到自己的指针,得不到其他线程的指针,这样就会互不干扰,各自私藏。

举例如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_LEN  (100)
pthread_key_t key;
pthread_once_t once_init = PTHREAD_ONCE_INIT;

void release_buffer(void* ptr)
{    
    printf("Thread %lx release buffer addr at %ld\n",pthread_self(),(long)ptr);
    free(ptr);
}
void create_key()
{   
    pthread_key_create(&key,release_buffer);
    printf("Thread %lx create key\n",pthread_self());
}


void gen_data(int* num_ptr)
{    
    int *ptr = NULL;
    pthread_once(&once_init,create_key);//一次性初始化,只会执行一次。
    ptr=(int*)pthread_getspecific(key);//获得key绑定的指针地址

    if(ptr == NULL)
    {   
        ptr=(int*)malloc(NUM_LEN*sizeof(int));
        pthread_setspecific(key,(void*)ptr);
        printf("Thread %lx: allocating buffer addr at %ld\n",pthread_self(),(long)ptr);
        ptr[0] = num_ptr[0];
     }
     else
	printf("Thread %lx: allocating buffer addr at %ld buffer[0] = %d  \n",pthread_self(),(long)ptr,ptr[0]);     
}

void* thread_fun(void* num_ptr)
{
    int i = 0;
    for(i = 0; i < 2; i++)//2次是为了证明buffer[0]不是覆盖碰巧对的,第一次赋值,第二次打印
    {
       gen_data((int*)num_ptr);
       sched_yield();//将处理器交给另一个等待的程序
     
    }
}


int main(int argc,char* argv[])
{   

    pthread_t th1,th2;
    int num[3] = {0,1,2};

    thread_fun((void*)(&num[0]));
    pthread_create(&th1,NULL,thread_fun,(void*)&num[1]);
    pthread_create(&th2,NULL,thread_fun,(void*)&num[2]);

    pthread_join(th1,NULL);
    pthread_join(th2,NULL);
    pthread_exit(0);
    return 0;
} 


三,线程取消

1,函数介绍

int pthread_cancel(pthread_t thread)
作用:发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止,只是提出请求.
      直到到达某个取消点(CancellationPoint)。取消点是线程检查是否被取消并按照请求进行动作的一个位置.

int pthread_setcancelstate(int state, int *oldstate)
作用: 设置取消状态使能或者不使能。
state:有两种值PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
       分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行。   
old_state:NULL或者存入原来的Cancel状态以便恢复。  

int pthread_setcanceltype(int type, int *oldtype)  
作用:设置本线程取消动作的执行时机
type:有两种取值PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,
      仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);
      oldtype如果不为NULL则存入运来的取消动作类型值。  

void pthread_testcancel(void)
作用:在不包含取消点,又需要取消点的地方创建一个取消点,线程取消功能处于启用状态且取消状态设置为推迟取消状态时,
      pthread_testcancel()函数有效。


2,三种取消状态
Off  
                 禁用取消
Deferred           推迟取消:在下一个取消点执行取消//系统默认
Asynchronous   异步取消:可以随时执行取消

(1)推迟取消:在下一个取消点执行取消
线程调用pthread_cancel函数后,被取消线程不会立即取消,仅仅在到达取消点时响应取消请求。
而取消点在如pthread_testcancel,sleep,pthread_cond_wait等处。

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

int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_fun(void *arg)
{
        //pthread_mutex_lock(&mutex);
        while(1)
        {
             if(++cnt%20==0)
                   pthread_testcancel(); //此处如果上琐,main函数上琐就会出现死琐,因为这里还未解锁线程就return啦     
        }
        //pthread_mutex_unlock(&mutex);
}

int main()
{
        pthread_t th;
       
        pthread_create(&th,NULL,thread_fun,NULL);
        
        sleep(1);
        pthread_cancel(th);

        void *result;
        pthread_join(th,&result);

        if(result==PTHREAD_CANCELED)
            printf("cancel point =  %d\n",cnt);
        else
            printf("cancel fail\n");

     pthread_mutex_lock(&mutex);
     pthread_mutex_unlock(&mutex);
       return 0;
}


(2)禁用取消

暂时在代码的那个区域停用取消

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

int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_fun(void *arg)
{
        int state;
        while(1)
        {
                if(++cnt < 100)
                        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&state);
                if(cnt%200 == 0)
                        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&state);
                
                pthread_testcancel();
        }
}
int main()
{
        pthread_t th;  
        pthread_create(&th,NULL,thread_fun,NULL);
        pthread_cancel(th);

        void *result;
        pthread_join(th,&result);

        if(result==PTHREAD_CANCELED)
            printf("cancel point =  %d\n",cnt);
        else
            printf("cancel fail\n");
        return 0;
}

(3).异步取消:可以随时执行取消,很危险的行为。

下面的例子你会发现你执行几次,每次cancel point的值都不一样,因为取消点不存在,不可控

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

int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread_fun(void *arg)
{
        int cancel_type;
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&cancel_type);
        while(1)cnt++;
}
int main()
{
        pthread_t th;  
        pthread_create(&th,NULL,thread_fun,NULL);
        sleep(1);
        pthread_cancel(th);

        void *result;
        pthread_join(th,&result);

        if(result==PTHREAD_CANCELED)
            printf("cancel point =  %d\n",cnt);
        else
            printf("cancel fail\n");
        return 0;
}

3,收尾清除工作

void pthread_cleanup_push(void (*routine) (void *), void *arg)//将清除函数加到栈中
void pthread_cleanup_pop(int execute)调用清除函数

注意点:

(1)采用先入后出的栈结构管理
(2)当所有活动的清除处理函数返回时,线程被终止。
(3)execute为0表示不执行,非0为执行;但不影响异常终止时清理函数的执行

举例前面所说的会出现死锁的问题就是资源锁为释放,这里有个清除函数就可以解决死锁问题。

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

int cnt = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void cleanup_fun(void *arg)
{
        printf("clean up\n");
        pthread_mutex_unlock(&mutex);
}
void *thread_fun(void *arg)
{
        pthread_cleanup_push(cleanup_fun,NULL);
        pthread_mutex_lock(&mutex);
        while(0)
        {
             if(++cnt%20==0)
                   pthread_testcancel(); //此处如果上琐,main函数上琐就会出现死琐,因为这里还未解锁线程就return啦,加入清除函数就OK  
             //pthread_cleanup_pop(0);   
        }
        pthread_mutex_unlock(&mutex);
        pthread_cleanup_pop(0);//0正常执行退出是不执行清除函数的,1无论何时都执行
        return NULL;
}

int main()
{
        pthread_t th;
       
        pthread_create(&th,NULL,thread_fun,NULL);
        
        sleep(1);
        pthread_cancel(th);

        void *result;
        pthread_join(th,&result);

        if(result==PTHREAD_CANCELED)
            printf("cancel point =  %d\n",cnt);
        else
            printf("cancel fail\n");

        pthread_mutex_lock(&mutex);
        pthread_mutex_unlock(&mutex);

        return 0;
}


四,实时调度

1, 三种调度策略:

SCHED_OTHER: 分时调度策略,系统创建线程时,默认的线程是SCHED_OTHER,所有的线程的优先级别都是0。
             系统使用这种调度策略,程序将无法设置线程的优先级。
SCHED_FIFO: 实时调度策略,先到先服务。一旦占用cpu则一直运行,或是自愿放弃。
             支持优先级的使用一直运行直 到  有更高优先级任务到达或自己放弃。

SCHED_RR:    实时调度策略,时间片轮转。支持优先级的使用当进程的时间片用完,系统将重新分配时间片,

             并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。


2,获取具体调度策略的静态优先级范围,各个调度策略支持的最大和最小的优先级可以通过下面的两个函数获得
int sched_get_priority_max(int policy);

int sched_get_priority_min(int policy);

举例如下:

#include <stdio.h>
#include <pthread.h>
#include <sched.h>
void print_priority_for_policy(int policy)
{
  printf("max_priority=%d\n",sched_get_priority_max(policy));
  printf("min_priority=%d\n",sched_get_priority_min(policy));
}
int main(void)
{
   //不同策略的优先级
   print_priority_for_policy(SCHED_FIFO);
   print_priority_for_policy(SCHED_RR);
   print_priority_for_policy(SCHED_OTHER);
}

3,调度策略设置以及获取
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);


4,用来设置和获得线程属性attr的调度参数param即设置或者获取当前线程的优先级
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

其中参数结构体
struct sched_param
{
    int __sched_priority; //所要设定的线程优先级
};

举例如下:

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

void print_policy(pthread_attr_t* attr_ptr)
{
  int policy;
  pthread_attr_getschedpolicy(attr_ptr,&policy);

  if(SCHED_FIFO == policy)
     printf("policy = SCHED_FIFO\n");
  else if(SCHED_RR == policy)
     printf("policy = SCHED_RR\n");
  else if(policy == SCHED_OTHER)
     printf("policy = SCHED_OTHER\n");
  else
     printf("policy = error\n");
}

void print_priority_for_policy(int policy)
{
  printf("max_priority=%d\n",sched_get_priority_max(policy));
  printf("min_priority=%d\n",sched_get_priority_min(policy));
}

void print_priority_for_param(pthread_attr_t* attr_ptr)
{
  struct sched_param param;
  pthread_attr_getschedparam(attr_ptr,¶m);
  printf("priority=%d\n",param.__sched_priority);
}

int main(void)
{
  //1,不同策略的优先级范围
  print_priority_for_policy(SCHED_FIFO);
  print_priority_for_policy(SCHED_RR);
  print_priority_for_policy(SCHED_OTHER);

  //2,初始化属性
  pthread_attr_t attr;
  pthread_attr_init(&attr);

  //3,该线程属性的默认策略值以及优先级
  print_policy(&attr);
  print_priority_for_param(&attr);

  //4,修改策略后的默认优先级以及修改后的优先级
  pthread_attr_setschedpolicy(&attr,SCHED_RR);
  print_policy(&attr);
  print_priority_for_param(&attr);

  struct sched_param param;
  param.__sched_priority = 98;
  pthread_attr_setschedparam(&attr, &param);
  print_priority_for_param(&attr);
  
  //5,继续修改策略以及该线程的默认优先级
  pthread_attr_setschedpolicy(&attr,SCHED_FIFO);
  print_policy(&attr);
  print_priority_for_param(&attr);

  //6,销毁对于属性
  pthread_attr_destroy(&attr);

  return 0;
}


五,线程和核实体






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数字乡村和智慧农业的数字化转型是当前农业发展的新趋势,旨在通过应用数字技术,实现农业全流程的再造和全生命周期的管理服务。中国政府高度重视这一领域的发展,提出“数字中国”和“乡村振兴”战略,以提升国家治理能力,推动城乡融合发展。 数字乡村的建设面临乡村治理、基础设施、产业链条和公共服务等方面的问题,需要分阶段实施《数字乡村发展战略纲要》来解决。农业数字化转型的需求包括满足市民对优质农产品的需求、解决产销对接问题、形成优质优价机制、提高农业劳动力素质、打破信息孤岛、提高农业政策服务的精准度和有效性,以及解决农业融资难的问题。 数字乡村建设的关键在于构建“1+3+4+1”工程,即以新技术、新要素、新商业、新农民、新文化、新农村为核心,推进数据融合,强化农业大数据的汇集功能。数字农业大数据解决方案以农业数字底图和数据资源为基础,通过可视化监管,实现区域农业的全面数字化管理。 数字农业大数据架构基于大数据、区块链、GIS和物联网技术,构建农业大数据中心、农业物联网平台和农村综合服务指挥决策平台三大基础平台。农业大数据中心汇聚各类涉农信息资源和业务数据,支持大数据应用。信息采集系统覆盖市、县、乡、村多级,形成高效的农业大数据信息采集体系。 农业物联网平台包括环境监测系统、视频监控系统、预警预报系统和智能控制系统,通过收集和监测数据,实现对农业环境和生产过程的智能化管理。综合服务指挥决策平台利用数据分析和GIS技术,为农业决策提供支持。 数字乡村建设包括三大服务平台:治理服务平台、民生服务平台和产业服务平台。治理服务平台通过大数据和AI技术,实现乡村治理的数字化;民生服务平台利用互联网技术,提供各类民生服务;产业服务平台融合政企关系,支持农业产业发展。 数字乡村的应用场景广泛,包括农业生产过程、农产品流通、农业管理和农村社会服务。农业生产管理系统利用AIoT技术,实现农业生产的标准化和智能化。农产品智慧流通管理系统和溯源管理系统提高流通效率和产品追溯能力。智慧农业管理通过互联网+农业,提升农业管理的科学性和效率。农村社会服务则通过数字化手段,提高农村地区的公共服务水平。 总体而言,数字乡村和智慧农业的建设,不仅能够提升农业生产效率和管理水平,还能够促进农村地区的社会经济发展,实现城乡融合发展,是推动中国农业现代化的重要途径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值