POSIX.1 之 Threads

概述 

        这一节先讲一下线程的基本应用作为开篇。

        A single flow of control within a process. Each thread has its own thread ID, scheduling priority and policy, errno value, floating point environment, thread-specific key/value bindings, and the required system resources to support a flow of control. Anything whose address may be determined by a thread, including but not limited to static variables, storage obtained via malloc(), directly addressable storage obtained through implementation-defined functions, and automatic variables, are accessible to all threads in the same process. (POSIX.1原文)。

        POSIX.1认为在进程当中,单个控制流被称为线程(thread)。每个线程都有其唯一的线程ID、调度优先级和策略、errno值、浮点环境、线程特定的键/值绑定,以及支持控制流所需的系统资源。 在一个进程中,任何可以通过线程确定其地址的实体,包括但不限于静态变量、通过malloc()函数获得的存储、通过实现定义函数获得的可直接寻址的存储,以及自动变量,都是该进程中所有线程可访问的。

        定义就这样了,那么线程它有什么优势呢?如下:

  1. 资源共享:同一进程中的多个线程可以共享该进程的资源,如内存空间、打开的文件、数据库连接等。这种共享机制减少了资源创建和销毁的开销,提高了资源利用率。
  2. 独立执行:每个线程都有自己的执行上下文,包括程序计数器、栈指针和寄存器状态等。这使得线程能够独立地执行代码,而不受其他线程的影响。
  3. 并发执行:多线程程序可以在多核或多CPU的计算机上并发执行,充分利用硬件资源。即使在单CPU的计算机上,线程也可以通过时间片轮转的方式实现伪并发执行,从而提高程序的吞吐量和响应性。
  4. 通信与同步:线程之间可以通过共享内存进行通信,也可以使用特定的同步机制(如互斥锁、条件变量等)来协调它们的执行顺序,确保数据的一致性和程序的正确性。

        当然优缺点总是并存的,这么牛B的线程也有其不好之处,那就是编程的复杂度。比如全局数据的共享问题、线程间的同步问题、各种锁的应用场景,等等。

函数函数

        这第一节就先介绍线程创建的几个基本函数,也是看手册的一些心得,欢迎大家一起讨论。

函数名称说明
ptherad_create();在进程中创建一个线程
pthread_exit(),退出线程或终止线程。
pthread_cancel()向指定线程发送一个取消线程的请求
pthread_join()线程回收
pthread_self()获取当前线程的线程ID
pthread_detach()标记指定线程的分离状态
pthread_equal()比较两个线程ID是否相同
pthread_attr_destroy()销毁线程属性
pthread_attr_init()初始化线程属性

pthread_create()

       pthread_create()在进程中创建一个新的线程。

int pthread_create(pthread_t * restrict thread,
        const pthread_attr_t *restrict attr, 
        void *(*start_routine)(void*),void *restrict arg);

        新线程将执行start_routine所引用的线程函数,“arg”是要传递给 start_routine 中的线程参数指针。在线程创建成功后,线程ID通过指针 thread 返回。

        函数定义中,用到了“restrict"限定符,用于告诉编译器,在指针的生命周期内,它指向的对象只能通过这个特定的指针来访问。即该指针是唯一的,没有其他指针指向该指针所指向的内存段。

        "thread":是pthread_t 类型指针,用来存储线程创建后保存线程ID的。

        "attr" : 指定的线程属性,若其指针为空,则采用默认线程参数进行创建。

        start_routine : 线程函数。

        "arg" : 是传递给线程的参数。

注:编译时一定要引用“-pthread",否则会报错。

pthread_exit()

void pthread_exit(void *retval)

        这个函数是用来终止调用它的线程的。指针 retval 所指向的数据会提供给任务何成功连接到终止线程的线程。一般情况下都是给NULL,如果是条件退出的话可以传递退出原因等参数。

pthread_cancel()

int pthread_cancel(pthread_t thread)

        该函数用来向指定线程(thread)发送“取消线程”的请求。目标线程什么时候取消取决于线程的可取消状态和类型。这个主要用于要干掉这个线程,但还要保证线程安全,即线程要在可取消状态下被干掉,这样可以在一定程度上保护进程的稳定。

pthread_join()

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

        该函数用来阻塞式等待线程 “thread” 终止,并将函数 pthread_exit() 函数所返回的值放到 value_ptr 所指向的位置。

pthread_self()

pthread_t pthread_self(void);

        获取当前线程的线程ID,手册上说这是个不会出错的函数。

pthread_attr_init()

int pthread_attr_init(pthread_attr_t *attr)

        依默认属性参数初始化指定的线程属性参数,初始化成功后会返回0,失败的话则会返回相应的错误码。只有初始化之后才可能通过相关的函数去配置属性参数。

pthread_attr_destroy()

int pthread_attr_destroy(pthread_attr_t *attr)

        销毁指定的线程属性参数。成功返回0。失败则会返回相应的错误代码。

pthread_detach()

int pthread_detach(pthread_t thread)

        将指定线程配置为分离状态,使其在线程结束时由系统直接回收线程所占用的资源。该函数并不会直接结束线程,它只是修改了线程结束时资源回收方式。

pthread_equal()

int pthread_equal(pthread_t t1, pthread_t t2);

        比较两个线程ID是否是相等的,如果相等则会返回一个非零的值,反之则会返回0。这又是一个号称不会失败的函数,不过在手册中说当t1/t2 不是线程ID时可能会返回任何值。

示例

        想来想去还是去抄了官方的示例过来,在其基础上稍做了一些修改,未尽之处大家多指教吧。



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

#include "test_ma.h"
#include <ctype.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>


#define handle_error_en(en, msg) \
    do {                         \
        errno = en;              \
        perror(msg);             \
        exit(EXIT_FAILURE);      \
    } while (0)

#define handle_error(msg)   \
    do {                    \
        perror(msg);        \
        exit(EXIT_FAILURE); \
    } while (0)

struct thread_info
{                          /* Used as argument to thread_start() */
    pthread_t thread_id;   /* ID returned by pthread_create() */
    int       thread_num;  /* Application-defined thread # */
    char*     argv_string; /* From command-line argument */
};

/* Thread start function: display address near top of our stack,
   and return upper-cased copy of argv_string */

static void* thread_start(void* arg)
{
    struct thread_info* tinfo = arg;
    char *              uargv, *p;

    printf("Thread %d: top of stack near %p; argv_string=%s\n", tinfo->thread_num, (void*)&p, tinfo->argv_string);

    uargv = strdup(tinfo->argv_string);
    if (uargv == NULL)
        handle_error("strdup");

    for (p = uargv; *p != '\0'; p++)
        *p = toupper(*p);

    return uargv;
}

int main(int argc, char* argv[])
{
    // 定义变量s,tnum,opt,num_threads,tinfo,stack_size,res
    int                 s, tnum, opt, num_threads = 0;
    struct thread_info* tinfo;
    pthread_attr_t      attr;
    int                 stack_size;
    void*               res;

    /* The "-s" option specifies a stack size for our threads */
    printf("Creating %d threads,argc[%d]\n", num_threads, argc);
    // 设置stack_size为-1
    stack_size = -1;
    // 循环获取参数,argc为命令行参数个数,argv为命令行参数数组,当返回“s"时表时获取了一个字符串
    while ((opt = getopt(argc, argv, "s:")) != -1) {
        // 根据参数选择执行操作
        switch (opt) {
            case 's':
                // 设置stack_size,将获得的这个字符串参数转换为10进制数
                stack_size = strtoul(optarg, NULL, 0);
                break;

            default:
                // 打印错误信息
                fprintf(stderr, "Usage: %s [-s stack-size] arg...\n", argv[0]);
                // 退出程序
                exit(EXIT_FAILURE);
        }
    }



    num_threads = argc - optind;

    printf("Creating %d threads,argc[%d],optind[%d]\n", num_threads, argc, optind);

    /* Initialize thread creation attributes */
    // 初始化线程创建属性
    s = pthread_attr_init(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_init");

    /* Set stack size for each thread, if requested */
    if (stack_size > 0) {
        s = pthread_attr_setstacksize(&attr, stack_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstacksize");
    }

    /* Allocate memory for pthread_create() arguments */

    tinfo = calloc(num_threads, sizeof(struct thread_info));
    if (tinfo == NULL)
        handle_error("calloc");

    /* Create one thread for each command-line argument */

    for (tnum = 0; tnum < num_threads; tnum++) {
        tinfo[tnum].thread_num  = tnum + 1;
        tinfo[tnum].argv_string = argv[optind + tnum];

        /* The pthread_create() call stores the thread ID into
           corresponding element of tinfo[] */
        if (tnum % 2)
            s = pthread_create(&tinfo[tnum].thread_id, &attr, &thread_function, &tinfo[tnum]);
        else
            s = pthread_create(&tinfo[tnum].thread_id, &attr, &thread_start, &tinfo[tnum]);
        if (s != 0)
            handle_error_en(s, "pthread_create");
    }

    /* Destroy the thread attributes object, since it is no
    longer needed */

    s = pthread_attr_destroy(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_destroy");

    /* Now join with each thread, and display its returned value */

    for (tnum = 0; tnum < num_threads; tnum++) {
        s = pthread_join(tinfo[tnum].thread_id, &res);
        if (s != 0)
            handle_error_en(s, "pthread_join");

        printf("Joined with thread %d; returned value was %s\n", tinfo[tnum].thread_num, (char*)res);
        free(res); /* Free memory allocated by thread */
    }

    free(tinfo);
    exit(EXIT_SUCCESS);
}

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值