`
lobin
  • 浏览: 430943 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多

 

pth安装

pth安装选项

--enable-shared[=PKGS]

编译动态库,默认编译

 

--enable-static[=PKGS]

编译静态库,默认编译

 

--enable-debug 开启debug安装debug版本,用于开发测试。指定这个选项安装,默认情况下,如果没有显式指定--enable-shared,将只会安装静态链接库。

 

--enable-pthread 支持pthread,默认不支持。

 

--with-mctx-mth=ID

指定上下文切换方式。

安装

./configure --prefix=/usr/local/pth-2.0.7

make

make install

写道
├─bin
│ pth-config

├─include
│ pth.h

├─lib
│ libpth.a
│ libpth.la

├─man
│ ├─man1
│ │ pth-config.1
│ │
│ └─man3
│ pth.3

└─share
└─aclocal
pth.m4

 

线程

pth通过pth_spawn创建一个线程,如果创建成功,返回一个pth_t类型的新创建的线程标识。

typedef struct pth_st *pth_t;

pth_t定义为struct pth_st的指针类型。

 

struct pth_st

TCB,也就是线程控制块,其定义为:

    /* thread control block */
struct pth_st {
    /* priority queue handling */
    pth_t          q_next;               /* next thread in pool                         */
    pth_t          q_prev;               /* previous thread in pool                     */
    int            q_prio;               /* (relative) priority of thread when queued   */

    /* standard thread control block ingredients */
    int            prio;                 /* base priority of thread                     */
    char           name[PTH_TCB_NAMELEN];/* name of thread (mainly for debugging)       */
    int            dispatches;           /* total number of thread dispatches           */
    pth_state_t    state;                /* current state indicator for thread          */

    /* timing */
    pth_time_t     spawned;              /* time point at which thread was spawned      */
    pth_time_t     lastran;              /* time point at which thread was last running */
    pth_time_t     running;              /* time range the thread was already running   */

    /* event handling */
    pth_event_t    events;               /* events the tread is waiting for             */

    /* per-thread signal handling */
    sigset_t       sigpending;           /* set    of pending signals                   */
    int            sigpendcnt;           /* number of pending signals                   */

    /* machine context */
    pth_mctx_t     mctx;                 /* last saved machine state of thread          */
    char          *stack;                /* pointer to thread stack                     */
    unsigned int   stacksize;            /* size of thread stack                        */
    long          *stackguard;           /* stack overflow guard                        */
    int            stackloan;            /* stack type                                  */
    void        *(*start_func)(void *);  /* start routine                               */
    void          *start_arg;            /* start argument                              */

    /* thread joining */
    int            joinable;             /* whether thread is joinable                  */
    void          *join_arg;             /* joining argument                            */

    /* per-thread specific storage */
    const void   **data_value;           /* thread specific  values                     */
    int            data_count;           /* number of stored values                     */

    /* cancellation support */
    int            cancelreq;            /* cancellation request is pending             */
    unsigned int   cancelstate;          /* cancellation state of thread                */
    pth_cleanup_t *cleanups;             /* stack of thread cleanup handlers            */

    /* mutex ring */
    pth_ring_t     mutexring;            /* ring of aquired mutex structures            */

#ifdef PTH_EX
    /* per-thread exception handling */
    ex_ctx_t       ex_ctx;               /* exception handling context                  */
#endif
};

线程属性

 

struct pth_attr_st {
    pth_t        a_tid;
    int          a_prio;
    int          a_dispatches;
    char         a_name[PTH_TCB_NAMELEN];
    int          a_joinable;
    unsigned int a_cancelstate;
    unsigned int a_stacksize;
    char        *a_stackaddr;
};
 

 

 

线程调度

优先级调度

 

优先级

分为3个优先级。标准优先级,最大优先级以及最小优先级。

    /* thread priority values */
#define PTH_PRIO_MAX                 +5
#define PTH_PRIO_STD                  0
#define PTH_PRIO_MIN                 -5

优先级队列

pth根据线程的状态各自创建一个优先级队列。

intern pth_pqueue_t pth_NQ;         /* queue of new threads                  */
intern pth_pqueue_t pth_RQ;         /* queue of threads ready to run         */
intern pth_pqueue_t pth_WQ;         /* queue of threads waiting for an event */
intern pth_pqueue_t pth_SQ;         /* queue of suspended threads            */
intern pth_pqueue_t pth_DQ;         /* queue of terminated threads           */

pth_NQ

新创建的线程进入此队列。

pth_RQ

线程就绪进入此队列

pth_WQ

线程等待事件进入此队列

pth_SQ

线程挂起进入此队列

pth_DQ

线程终止进入此队列。

 

优先级队列实现

在实现优先级队列的时候,我们可能会通过如下方式实现。 

写道

 

pth通过双链表实现优先级队列。在这个双链表中,队头的优先级越高,往后优先级越低,队尾的优先级最低。

/* thread priority queue */
struct pth_pqueue_st {
    pth_t q_head;
    int   q_num;
};
typedef struct pth_pqueue_st pth_pqueue_t;

结构体struct pth_pqueue_st只定义了队头及队列中节点的数目。主要结构在struct pth_st中定义,包括优先级等。

 

调度器

 

 

上下文切换

上下文切换方式

支持两种上下文切换方式:mcsc和sjlj。mcsc是通过ucontext方式来实现上下文切换,这是linux下协程的实现方式。sjlj是通过pth_siglongjmp(siglongjmp/longjmp/_longjmp)的方式来实现上下文切换。

 

上下文切换方式在编译的时候确定,其实是在编译前配置的时候确定,在./configure的时候指定--with-mctx-mth,可以指定这两种切换方式。

写道
--with-mctx-mth=ID force mctx method (mcsc,sjlj)

 

在pth_acdef.h.in配置头文件中,有一个PTH_MCTX_MTH_use的定义。指定./configure之后,会根据这个配置头文件生成头文件pth_acdef.h。

/* define for machine context method */
#undef PTH_MCTX_MTH_use

在./configure的时候指定--with-mctx-mth,可以指定--with-mctx-mth=mcsc或者--with-mctx-mth=sjlj,默认不指定的话就是mcsc,如果采用的是mcsc,配置之后的定义如下:

/* define for machine context method */
#define PTH_MCTX_MTH_use PTH_MCTX_MTH_mcsc

 

初始化

pth在使用之前需要init

pth_init();

使用完时候需要kill

pth_kill();

 

int pth_init(void)
{
    pth_attr_t t_attr;

    /* support for implicit initialization calls
       and to prevent multiple explict initialization, too */
    if (pth_initialized)
        return pth_error(FALSE, EPERM);
    else
        pth_initialized = TRUE;

    pth_debug1("pth_init: enter");

    /* initialize syscall wrapping */
    pth_syscall_init();

    /* initialize the scheduler */
    if (!pth_scheduler_init()) {
        pth_shield { pth_syscall_kill(); }
        return pth_error(FALSE, EAGAIN);
    }

#ifdef PTH_EX
    /* optional support for exceptional handling */
    __ex_ctx       = pth_ex_ctx;
    __ex_terminate = pth_ex_terminate;
#endif

    /* spawn the scheduler thread */
    t_attr = pth_attr_new();
    pth_attr_set(t_attr, PTH_ATTR_PRIO,         PTH_PRIO_MAX);
    pth_attr_set(t_attr, PTH_ATTR_NAME,         "**SCHEDULER**");
    pth_attr_set(t_attr, PTH_ATTR_JOINABLE,     FALSE);
    pth_attr_set(t_attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_DISABLE);
    pth_attr_set(t_attr, PTH_ATTR_STACK_SIZE,   64*1024);
    pth_attr_set(t_attr, PTH_ATTR_STACK_ADDR,   NULL);
    pth_sched = pth_spawn(t_attr, pth_scheduler, NULL);
    if (pth_sched == NULL) {
        pth_shield {
            pth_attr_destroy(t_attr);
            pth_scheduler_kill();
            pth_syscall_kill();
        }
        return FALSE;
    }

    /* spawn a thread for the main program */
    pth_attr_set(t_attr, PTH_ATTR_PRIO,         PTH_PRIO_STD);
    pth_attr_set(t_attr, PTH_ATTR_NAME,         "main");
    pth_attr_set(t_attr, PTH_ATTR_JOINABLE,     TRUE);
    pth_attr_set(t_attr, PTH_ATTR_CANCEL_STATE, PTH_CANCEL_ENABLE|PTH_CANCEL_DEFERRED);
    pth_attr_set(t_attr, PTH_ATTR_STACK_SIZE,   0 /* special */);
    pth_attr_set(t_attr, PTH_ATTR_STACK_ADDR,   NULL);
    pth_main = pth_spawn(t_attr, (void *(*)(void *))(-1), NULL);
    if (pth_main == NULL) {
        pth_shield {
            pth_attr_destroy(t_attr);
            pth_scheduler_kill();
            pth_syscall_kill();
        }
        return FALSE;
    }
    pth_attr_destroy(t_attr);

    /*
     * The first time we've to manually switch into the scheduler to start
     * threading. Because at this time the only non-scheduler thread is the
     * "main thread" we will come back immediately. We've to also initialize
     * the pth_current variable here to allow the pth_spawn_trampoline
     * function to find the scheduler.
     */
    pth_current = pth_sched;
    pth_mctx_switch(&pth_main->mctx, &pth_sched->mctx);

    /* came back, so let's go home... */
    pth_debug1("pth_init: leave");
    return TRUE;
}

 

 

创建线程

 

pth_t pth_spawn(pth_attr_t attr, void *(*func)(void *), void *arg)
{
    pth_t t;
    unsigned int stacksize;
    void *stackaddr;
    pth_time_t ts;

    pth_debug1("pth_spawn: enter");

    /* consistency */
    if (func == NULL)
        return pth_error((pth_t)NULL, EINVAL);

    /* support the special case of main() */
    if (func == (void *(*)(void *))(-1))
        func = NULL;

    /* allocate a new thread control block */
    stacksize = (attr == PTH_ATTR_DEFAULT ? 64*1024 : attr->a_stacksize);
    stackaddr = (attr == PTH_ATTR_DEFAULT ? NULL    : attr->a_stackaddr);
    if ((t = pth_tcb_alloc(stacksize, stackaddr)) == NULL)
        return pth_error((pth_t)NULL, errno);

    /* configure remaining attributes */
    if (attr != PTH_ATTR_DEFAULT) {
        /* overtake fields from the attribute structure */
        t->prio        = attr->a_prio;
        t->joinable    = attr->a_joinable;
        t->cancelstate = attr->a_cancelstate;
        t->dispatches  = attr->a_dispatches;
        pth_util_cpystrn(t->name, attr->a_name, PTH_TCB_NAMELEN);
    }
    else if (pth_current != NULL) {
        /* overtake some fields from the parent thread */
        t->prio        = pth_current->prio;
        t->joinable    = pth_current->joinable;
        t->cancelstate = pth_current->cancelstate;
        t->dispatches  = 0;
        pth_snprintf(t->name, PTH_TCB_NAMELEN, "%s.child@%d=0x%lx",
                     pth_current->name, (unsigned int)time(NULL),
                     (unsigned long)pth_current);
    }
    else {
        /* defaults */
        t->prio        = PTH_PRIO_STD;
        t->joinable    = TRUE;
        t->cancelstate = PTH_CANCEL_DEFAULT;
        t->dispatches  = 0;
        pth_snprintf(t->name, PTH_TCB_NAMELEN,
                     "user/%x", (unsigned int)time(NULL));
    }

    /* initialize the time points and ranges */
    pth_time_set(&ts, PTH_TIME_NOW);
    pth_time_set(&t->spawned, &ts);
    pth_time_set(&t->lastran, &ts);
    pth_time_set(&t->running, PTH_TIME_ZERO);

    /* initialize events */
    t->events = NULL;

    /* clear raised signals */
    sigemptyset(&t->sigpending);
    t->sigpendcnt = 0;

    /* remember the start routine and arguments for our trampoline */
    t->start_func = func;
    t->start_arg  = arg;

    /* initialize join argument */
    t->join_arg = NULL;

    /* initialize thread specific storage */
    t->data_value = NULL;
    t->data_count = 0;

    /* initialize cancellation stuff */
    t->cancelreq   = FALSE;
    t->cleanups    = NULL;

    /* initialize mutex stuff */
    pth_ring_init(&t->mutexring);

#ifdef PTH_EX
    /* initialize exception handling context */
    EX_CTX_INITIALIZE(&t->ex_ctx);
#endif

    /* initialize the machine context of this new thread */
    if (t->stacksize > 0) { /* the "main thread" (indicated by == 0) is special! */
        if (!pth_mctx_set(&t->mctx, pth_spawn_trampoline,
                          t->stack, ((char *)t->stack+t->stacksize))) {
            pth_shield { pth_tcb_free(t); }
            return pth_error((pth_t)NULL, errno);
        }
    }

    /* finally insert it into the "new queue" where
       the scheduler will pick it up for dispatching */
    if (func != pth_scheduler) {
        t->state = PTH_STATE_NEW;
        pth_pqueue_insert(&pth_NQ, t->prio, t);
    }

    pth_debug1("pth_spawn: leave");

    /* the returned thread id is just the pointer
       to the thread control block... */
    return t;
}
创建线程的时候需要传入线程属性,线程执行的函数例程,以及传给这个函数例程的参数。其中函数例程原型定义为void *(*func)(void *),和pthread一样,这个必须指定。

 

如果不想自己指定线程属性,可以指定默认线程属性PTH_ATTR_DEFAULT

 

#define PTH_ATTR_DEFAULT (pth_attr_t)(0)

 

关于这个函数例程,有个特殊的情况是,传入-1的时候,表示主线程,这种情况会将函数例程设置为NULL。

 

接着为新创建的线程分配一个TCB,即线程控制块,同时初始化TCB,在初始化TCB的时候:

 

主要初始化线程名,线程栈大小,栈空间,栈保护空间,优先级,是否joinable,是否可取消,

 

如果没有指定线程名,如果pth_current(指向当前线程的TCB)为NULL,线程名为user/%x,其中%x为当前时间,如果pth_current(指向当前线程的TCB)不为NULL,线程名为%s.child@%d=0x%lx,其中%s为当前线程名,%d为当前时间,%lx为当前线程的TCB地址。

 

线程栈大小默认为64k,如果指定的线程栈大小大于0小于SIGSTKSZ,会将线程栈大小设置为SIGSTKSZ。

这里有个特殊情况,如果是主线程的话,在为主线程分配TCB的时候,指定的线程栈大小为0。因为不需要给主线程分配栈空间。同时在为主线程分配TCB的时候,线程栈地址指定为NULL。

 

线程栈空间如果没有指定的话,会分配一块空间给这个新创建的线程。

 

初始化后还会在栈的高地址或低地址写入0xDEAD(4个字节),DEAD?不清楚什么意图。

 

如果没有指定线程属性,将从pth_current(指向当前线程的TCB)继承线程优先级,是否joinable,是否可取消状态。

 

还会设置线程执行的函数例程以及传入的参数。

 

初始化的时候不会为线程分配TLS。

 

新创建的线程状态为PTH_STATE_NEW。

 

新线程创建后将会放入pth_NQ优先级队列中。

 

 

 

创建线程

 

#include <stdio.h>
#include <pth.h>

void* start_routine(void *arg) 
{
  char* name = (char *) arg;
  printf("thread %s called.\n", name);
  return NULL;
}

int main()
{
  pth_t pth;
  void *pth_exit;

  pth_init();
  pth = pth_spawn(PTH_ATTR_DEFAULT, start_routine, (void *) "#1");

  pth_join(pth, &pth_exit);
  pth_kill();
  return 0;
}

 

 

指定线程属性

 

#include <stdio.h>
#include <pth.h>

void* start_routine(void *arg) 
{
  char* name = (char *) arg;
  printf("thread %s called.\n", name);
  return NULL;
}

int main()
{
  pth_attr_t pth_attr;
  pth_t pth;
  void *pth_exit;

  if (! pth_init())
  {
    printf("pth init err\n");
    return 1;
  }
  pth_attr = pth_attr_new();

  pth = pth_spawn(pth_attr, start_routine, (void *) "#1");

  pth_join(pth, &pth_exit);
  if (! pth_kill())
  {
    printf("pth kill err\n");
    return 1;
  }
  return 0;
}

 

创建多个线程

#include <stdio.h>
#include <unistd.h>
#include <pth.h>

void* start_routine(void *arg) 
{
  unsigned i = 0;
  char* name = (char *) arg;
  printf("thread %s called.\n", name);
  while (++i && i <= 10)
  {
    sleep(1); // sleep 1 seconds.
    printf("%s: %d\n", name, i);
  }
  return NULL;
}

int main()
{
  pth_t pth1, pth2;
  void *pth_exit;
  if (! pth_init())
  {
    printf("pth init err\n");
    return 1;
  }
  pth1 = pth_spawn(PTH_ATTR_DEFAULT, start_routine, (void *) "#1");
  pth2 = pth_spawn(PTH_ATTR_DEFAULT, start_routine, (void *) "#2");

  pth_join(pth1, &pth_exit);
  pth_join(pth2, &pth_exit);
  if (! pth_kill())
  {
    printf("pth kill err\n");
    return 1;
  }
  return 0;
}

编译

# gcc -I /usr/local/pth-2.0.7/include/ -L /usr/local/pth-2.0.7/lib pth_multi_test2.c -o pth_multi_test2 -lpth

# ldd pth_multi_test2

linux-gate.so.1 =>  (0x00cdd000)

libpth.so.20 => /usr/lib/libpth.so.20 (0x00c35000)

libc.so.6 => /lib/libc.so.6 (0x00356000)

/lib/ld-linux.so.2 (0x800ec000)

运行

# ./pth_multi_test2 

thread #1 called.

#1: 1

#1: 2

#1: 3

#1: 4

#1: 5

#1: 6

#1: 7

#1: 8

#1: 9

#1: 10

thread #2 called.

#2: 1

#2: 2

#2: 3

#2: 4

#2: 5

#2: 6

#2: 7

#2: 8

#2: 9

#2: 10

从运行结果看线程1和2没有一点交替运行。结果感觉不正常,多次运行结果都是这样。

 

 

 

 

分享到:
评论

相关推荐

    u2net网络的预训练模型u2net.pth

    标题“u2net网络的预训练模型u2net.pth”指的是U-Net神经网络的一个预先训练好的权重模型,文件名“u2net.pth”是保存该模型权重的具体文件。U-Net网络是一种在图像分割任务中广泛应用的卷积神经网络(CNN)架构,...

    detection_Resnet50_Final.pth, Resnet50_Final.pth

    标题中的“detection_Resnet50_Final.pth”和“Resnet50_Final.pth”两个文件名,以及描述中的“md5: bce939bc22d8cec91229716dd932e”,揭示了与深度学习相关的知识点,特别是图像检测领域的一个模型权重文件。...

    RealESRGAN-x4plus.pth

    《RealESRGAN-x4plus.pth:高分辨率图像超分辨率技术的深度学习模型》 在数字图像处理领域,超分辨率重建技术(Super-Resolution)一直备受关注,它旨在通过算法提升低分辨率图像的质量,使其接近或达到原生高分辨...

    resnet18-5c106cde.pth和resnet101-5d3b4d8f.pth

    本篇将详细讲解标题中的两个预训练模型:“resnet18-5c106cde.pth”和“resnet101-5d3b4d8f.pth”,它们是PyTorch官网提供的ResNet网络的不同版本。 ResNet,全称为残差网络(Residual Network),由Kaiming He等人...

    model-mobilefacenet.pth

    在使用"model_mobilefacenet.pth"这个文件时,首先需要将其解压并加载到相应的深度学习框架中,如PyTorch或TensorFlow。然后,通过预训练的模型权重,我们可以对新的面部图像进行特征提取,进一步进行识别或匹配。在...

    Unet训练需要使用的权重文件unet_voc.pth

    "unet_voc.pth" 文件是Unet模型在VOC(PASCAL Visual Object Classes)数据集上训练得到的权重文件。 VOC数据集是一个多类别的图像识别和分割数据集,包含20个不同的物体类别,用于训练和评估计算机视觉算法。在...

    GFPGANv1.4.pth

    GFPGANv1.4.pth下载

    第68天:内网安全-域横向PTH&PTK&PTT哈希票据传递1

    内网安全是一个重要的议题,尤其是在企业环境中,域横向PTH、PTK、PTT哈希票据传递是其中的关键攻击手段。这些方法主要针对Kerberos协议的弱点,利用NTLM哈希、Kerberos票据和AES密钥来绕过认证过程,从而在内部网络...

    stable-diffusion-webui codeformer.pth

    就我而言,我在“\models\Codeformer”上的 Codeformer.pth 已损坏。替换为手动安装的https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth。 解决了这个问题。 ——————————...

    resnet18-5c106cde.pth

    标题中的"resnet18-5c106cde.pth"是一个预训练模型的权重文件,这在深度学习领域非常常见。ResNet18是Residual Network(残差网络)系列模型的一个变体,由Kaiming He等人在2015年提出。这个模型因其18层的深度而...

    resnet152-b121ed2d.pth

    标题中的"resnet152-b121ed2d.pth"是一个模型权重文件,它属于计算机视觉(CV)领域中的ResNet-152网络架构。ResNet,全称是深度残差网络(Deep Residual Network),由Kaiming He等人在2015年的ImageNet挑战赛上...

    easyOCR_pth.zip

    这个“easyOCR_pth.zip”压缩包包含的是EasyOCR模型的权重文件,可能是一个预训练模型或者用户自定义训练的模型,用于识别图像中的文字。 在深度学习领域,OCR技术利用神经网络模型来识别图像中的文本,将其转化...

    srcnn_pth_模型_下载.rar

    标题中的"srcnn_pth_模型_下载.rar"指的是一个RAR格式的压缩包,其中包含SRCNN(Super-Resolution Convolutional Neural Network)模型的权重文件。SRCNN是一种早期的深度学习模型,专用于图像超分辨率,即提升低...

    vgg16-397923af.pth

    模型的权重文件"vgg16-397923af.pth"是一个预训练的权重集合,用于快速部署和在新的图像识别任务上进行微调。文件名中的"397923af"通常是一个哈希值,用来唯一标识这个特定的权重版本。这个文件可能是PyTorch框架下...

    u2net.pth训练包压缩包

    本训练包“u2net.pth”是专门为U2Net模型设计的预训练权重文件,它包含了模型在大量数据上训练得到的参数,可以帮助用户快速部署和应用该模型,无需从零开始训练。下面将详细解析U2Net模型以及这个训练包的核心内容...

    PTH08T240WAD

    根据给定文件信息,我们可以提炼出以下关于PTH08T240WAD电源模块的知识点: 1. PTH08T240WAD是一种高性能的电源模块,具备非隔离的特性,可以提供高达10安培的输出电流。 2. 该模块的输入电压范围很宽,介于4.5伏...

    vgg16_bn-6c64b313.pth

    标题中的"vgg16_bn-6c64b313.pth"是一个预训练模型的权重文件,常用于计算机视觉(CV)领域的深度学习任务。这个文件是VGG16网络模型的一个版本,带有批归一化(Batch Normalization,BN)层,其哈希值为"6c64b313...

    Openpose的pth模型文件,包含pose及hands

    - `body_pose_model.pth` 和 `hand_pose_model.pth` 是PyTorch格式的预训练模型。尽管原始模型是基于Caffe训练的,但这些.pth文件是为了在PyTorch环境中使用。PyTorch是一个动态计算图的深度学习框架,更便于模型的...

    ctdet_coco_dla_2x.pth

    《深度学习中的预训练模型:ctdet_coco_dla_2x.pth》 在现代计算机视觉领域,预训练模型已经成为解决复杂任务的关键工具。本文将深入探讨“ctdet_coco_dla_2x.pth”,一个在GoogleDrive上共享的预训练模型,其主要...

    dla34-ba72cf86.pth

    标题 "dla34-ba72cf86.pth" 和描述中的内容 "dla34-ba72cf86.pth" 提供了一个关键线索,这表明我们正在讨论一个与DLA34网络架构相关的权重文件。在深度学习领域,这种.pth文件通常存储着经过训练的模型参数,便于...

Global site tag (gtag.js) - Google Analytics