返回顶部
首页 > 资讯 > 后端开发 > JAVA >C 语言编程 — pthread 用户线程操作
  • 674
分享到

C 语言编程 — pthread 用户线程操作

c语言javajvm 2023-09-10 21:09:04 674人浏览 安东尼
摘要

目录 文章目录 目录pthread 线程库TCB 结构体线程的生命周期管理线程的合并与分离pthread_create() 创建线程pthread_join() 合并线程pthread_exi

目录

文章目录

pthread 线程

pthread(POSIX Threads)是一套符合 POSIX(Portable Operating System Interface,可移植操作系统接口)的 User Thread 操作 api 标准,定义了一组线程相关的函数(60 多个)和数据类型。pthread API 可以用于不同的操作系统上,因此被称为可移植的线程 API。

在版本较新的 linux Kernel 中,pthread API 的具体实现是 NPTL(Native POSIX Thread Library)。为了方便描述,在后文中我们使用 pthread 来统称。

  • 实现源码https://GitHub.com/lattera/glibc/blob/master/nptl/pthread_create.c
  • 文档:Https://docs.oracle.com/cd/E19253-01/819-7051/attrib-74380/index.html

pthread 线程库围绕 struct pthread 提供了一系列的接口,用于完成 User Thread 创建、调度、销毁等一系列管理。

在这里插入图片描述

TCB 结构体

在 pthread 中,使用 TCB(Thread Control Block,线程控制块)来存储 User Thread 的所有信息,TCB 的体量会比 PCB 小非常多。对应的 pthread 结构体如下:

// glibc/nptl/descr.hstruct pthread {    struct pthread *self;           // 指向自身的指针    struct __pthread_internal_list *thread_list;  // 线程列表,指向线程列表的指针,用于实现线程池    void *(*start_routine)(void*);  // 线程的入口函数,由 pthread_create() 函数传入;    void *arg;                      // 线程的入口函数参数,由 pthread_create() 函数传入;    void *result;                   // 线程的返回值,由线程的入口函数返回;    pthread_attr_t *attr;           // 线程的属性,包括栈保护区大小、调度策略等,由 pthread_create() 函数传入;    pid_t tid;                      // 线程的唯一标识符,由 Kernel 分配;    struct timespec *waiters;       // 等待的时间戳    size_t guardsize;               // 栈保护区大小    int sched_policy;               // 调度策略    struct sched_param sched_params;// 调度参数    void *specific_1stblock;        // 线程私有数据的第一个块    struct __pthread_internal_slist __cleanup_stack;  // 清理函数栈    struct __pthread_mutex_s *mutex_list;  // 线程持有的互斥列表    struct __pthread_cond_s *cond_list;    // 线程等待的条件变量列表    unsigned int detach_state:2;     // 线程分离状态,包括分离和未分离两种;    unsigned int sched_priority:30;  // 线程的调度优先级    unsigned int errno_val;          // 线程的错误码};

线程的生命周期管理

线程的合并与分离

对于 User Thread 的生命周期管理,首先要明确线程合并和线程分离的概念。

线程的合并与分离是指在多线程程序中,对于已经创建的线程进行结束和回收资源的 2 种操作方式。

  • 线程的合并:指等待某个线程结束后,主线程再继续执行资源回收。
  • 线程的分离:指线程结束后会自动释放资源,不需要等待主线程回收。

需要注意的是,线程的合并和分离操作都必须在目标线程执行结束之前进行,并且必须二选一,否则会导致内存泄露甚至崩溃。

pthread_create() 创建线程

函数作用:用于创建一条新的对等线程,并指定线程的入口函数和参数。pthread 库就会为 User Thread 分配 TCB、PC(程序计数器)、ReGISters(寄存器)和 Stack(栈)等资源。并将其加入到 Thread Queue 中等待执行。直到 User Thread 被调度到 CPU 时,开始执行线程入口函数。

函数原型

  • thread 参数:是一个 pthread_t 类型指针,用于存储 TID。
  • attr 参数:是一个 pthread_attr_t 类型指针,用于指定线程的属性,通常为 NULL。
  • start_routine 参数:线程入口函数,是一个 void* 类型函数指针(或直接使用函数名)。线程入口函数必须是一个 static 静态函数或全局函数,因为 pthread 会把线程入口函数的返回值传递到 pthread_join() 中,所以需要能够找到它。
  • arg 参数:线程参数,是一个 void* 类型参数。
  • 函数返回值
    • 成功:返回 0;
    • 失败:返回 -1;
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,                   void *(*start_routine) (void *), void *arg);

pthread_join() 合并线程

函数作用:执行线程合并。阻塞当前的主线程,直到指定线程执行结束,然后获得线程的执行结果,并释放线程的资源。

函数原型

  • thread 参数:指定等待的 TID。
  • retval:是一个指向指针的指针类型,用于存储线程的结果返回。
int pthread_join(pthread_t thread, void **retval);

在这里插入图片描述

pthread_exit() 线程主动退出

函数作用:线程主动终止自己,返回结果到 pthread_join()。需要注意的是,Main Thread 不应该调用 pthread_exit(),这样会退出整个 User Process。

函数原型

  • retval:是一个指针类型,用于存储退出码。如果不需要返回值,则设置为 NULL。
void pthread_exit(void *retval);

在这里插入图片描述

pthread_detach() 分离线程

函数作用:执行线程分离。将指定的线程标记为 “可分离的“,表示该线程在执行结束后会自动释放资源(由资源自动回收机制完成),无需等待主线程回收。另一方面,这也意味这主线程无法获得线程的返回值。

函数原型

  • thread 参数:指定 TID。
int pthread_detach(pthread_t thread);

线程的属性

可以在 pthread_create() 新建线程时,直接指定线程的属性,也可以更改已经存在的线程的属性,包括:

  • 线程分离属性;
  • LWP 绑定属性;
  • CPU 亲和性属性;
  • 调度属性;
  • 等等。
// 定义一个 pthread attribute 实例。pthread_attr_t attr;// 初始化一个 pthread attribute 实例。int pthread_attr_init(pthread_attr_t *attr);// 清除一个 pthread attribute 实例。int pthread_attr_destory(pthread_attr_t *attr);

线程分离属性

线程分离属性,即:将线程设定为 “可分离的"。

函数原型

  • attr:指定一个 pthread attribute 实例。
  • detachstate:指定 attr 的分离属性:
    • PTHREAD_CREATE_DETACHED:指示线程是分离的。
    • PTHREAD_CREATE_JOINABLE:默认属性,指示线程是合并的,需要主线程调用 pthread_join() 来等待并释放资源。
pthread_attr_setdetachstat(pthread_attr_t *attr, int detachstate);

设定属性后不需要再通过 pthread_detach() 重复设定。

LWP 绑定属性

POSIX 标准引入了 “线程竞争域“ 的概念,即:User Threads 对 CPU 资源发起竞争的范围,并要求至少要实现下列 2 种范围之一:

  1. PTHREAD_SCOPE_PROCESS:User Threads 在 User Process 范围内竞争 CPU 资源。
  2. PTHREAD_SCOPE_SYSTEM:User Threads 在 System 范围内竞争 CPU 资源。

相应的,pthread API 库也提供了 pthread_attr_setscope() 接口来设定 User Threads 的竞争范围。但是,实际上 Linux NPTL 只实现了 PTHREAD_SCOPE_SYSTEM 这一种方式。

具体而言就是 LWP(Light Weight Process)的实现。在还没有 pthread 线程库的早期版本的 Linux 中,只有 Kernel Thread 的概念,User Process 只能通过 kthread_crearte SCI(系统调用接口)来创建 Thread。但这种方式显然会存在 User Space(User Process)和 Kernel Space(Kernel Thread)之间频繁的切换。

为了解决这个问题,POSIX 标准引入了 User Thread 和 LWP 的概念,最早在 Solaris 操作系统中实现。之所以要同时引入 LWP 的目的是为了让实现 User Thread 的 pthread API 接口能够在不同的操作系统中保持良好的兼容性。

而 Linux NPTL 则将 LWP 作为 User Thread 和 Kernel Thread 之间建立映射关系的桥梁,并让 User Threads 能够竞争全局的 CPU 资源,以此来发挥多核处理器平台的并行优势。

当调用 pthread_create() 新建多个 User Threads 时,Kernel 会为这些 User Threads 创建少量的 LWPs,并建立 M:N 的映射关系。这个映射过程是由 Kernel 完成的,开发者无法手动干预。

在这里插入图片描述

CPU 亲和性属性

在 Kernel 中,LWP 同样作为可调度单元,与 kthread_create() 创建的 Kernel Thread 一般,可以被 Kernel Scheduler 识别并根据调度策略调度到不同的 CPU 上执行。

默认情况下,User Thread 依靠 LWP 的可调度能力,会被 Kernel 尽力而为的分配到多个不同的 CPU cores 上执行,以达到负载均衡。但这种分配是随机的,不保证 User Thread 最终在那个 Core 上执行。

相对的,可以通过修改 User Threads 的 CPU 亲和性属性让它们在指定的 cpuset 中竞争。

函数原型

  • attr:指定一个 pthread attribute 实例。
  • cpusetsize:指示 cpuset 实例的大小。
  • cpuset:指示 cpuset 实例,通过 中定义的函数进行初始化和操作。
int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);

调度属性

User Thread 的调度属性有 3 类,分别是:调度算法、调度优先级、调度继承权。

调度算法,函数原型

  • attr:指定一个 pthread attribute 实例。
  • policy:指定调度算法:
    • SCHED_OTHER:Linux 私有,默认采用,用于非实时应用程序。
    • SCHED_FIFO(先进先出):POSIX 标准,用于实时应用程序。
    • SCHED_RR(轮询):POSIX 标准,用于实时应用程序。
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);

调度优先级,函数原型:只在 SCHED_FIFO 和 SCHED_RR 等实时调度算法中生效,User Process 需要以 root 权限运行,且需要显式放弃父线程的继承权。

  • attr:指定一个 pthread attribute 实例。
  • param:指向了一个 sched_param 结构体,其中 sched_priority 字段用于指定优先值,范围 1~99。
struct sched_param {int sched_priority;char __opaque[__SCHED_PARAM_SIZE__]; };int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);

调度继承权,函数原型:子线程是否继承父线程的调度算法和调度优先级。

  • attr:指定一个 pthread attribute 实例。
  • inheritsched
    • PTHREAD_EXPLICIT_SCHED:不继承。
    • PTHREAD_INHERIT_SCHED:继承,默认。
int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);

多核平台并行编程示例

实践多线程的目的往往在于提升应用程序的执行性能,通常有并发和并行这 2 种方式:

  1. 并发程序:并发指在同一时间段内,多线程在同一个 CPU 上执行。并发程序不强制要求 CPU 具备多核计算能力,只要求多个线程在同一个 Core 上进行 “分时轮询” 处理,以此在宏观上实现多线程同时执行的效果。并发程序的执行通常是不确定的,这种不确定性来源于资源之间的相关依赖和竞态条件,可能导致执行的线程间相互等待(阻塞)。并发程序通常是有状态的(非幂等性)。

  2. 并行程序:并行指在同一时刻内,多线程在不同的 CPU core 上同时执行。并行程序会强制要求 CPU 具备多核计算能力,并行程序的每个执行模块在逻辑上都是独立的,即线程执行时可以独立地完成任务,从而做到同一时刻多个指令能够同时执行。并行程序通常是无状态的(幂等性)。

示例程序:

#define _GNU_SOURCE // 用于启用一些非标准的、GNU C 库扩展的特性,例如: 中的 CPU_ZERO 和 CPU_SET 函数。#include #include #include #include #include #define THREAD_COUNT 12  // 12 个对等线程void show_thread_sched_policy_and_cpu(int threadno){    int cpuid;    int policy;    struct sched_param param;    cpuid = sched_getcpu();    pthread_getschedparam(pthread_self(), &policy, &param);    printf("Thread %d is running on CPU %d, ", threadno, cpuid);    switch (policy)    {    case SCHED_OTHER:        printf("SCHED_OTHER\n", threadno);        break;    case SCHED_RR:        printf("SCHDE_RR\n", threadno);        break;    case SCHED_FIFO:        printf("SCHED_FIFO\n", threadno);        break;    default:        printf("UNKNOWN\n");    }}void *thread_func(void *arg){    int i, j;    long threadno = (long)arg;    printf("thread %d start\n", threadno);    sleep(1);    show_thread_sched_policy_and_cpu(threadno);    for (i = 0; i < 10; ++i)    {        // 适当调整执行时长        for (j = 0; j < 10000000000; ++j)        {        }    }    printf("thread %d exit\n", threadno);    return NULL;}int main(int arGC, char *argv[]){    long i;    int cpuid;    cpu_set_t cpuset;    pthread_attr_t attr[THREAD_COUNT];    pthread_t pth[THREAD_COUNT];    struct sched_param param;    // 初始化线程属性    for (i = 0; i < THREAD_COUNT; ++i)        pthread_attr_init(&attr[i]);    // 调度属性设置    for (i = 0; i < THREAD_COUNT / 2; ++i)    {        param.sched_priority = 10;        pthread_attr_setschedpolicy(&attr[i], SCHED_FIFO);        pthread_attr_setschedparam(&attr[i], &param);        pthread_attr_setinheritsched(&attr[i], PTHREAD_EXPLICIT_SCHED);    }    for (i = THREAD_COUNT / 2; i < THREAD_COUNT; ++i)    {        param.sched_priority = 20;        pthread_attr_setschedpolicy(&attr[i], SCHED_RR);        pthread_attr_setschedparam(&attr[i], &param);        pthread_attr_setinheritsched(&attr[i], PTHREAD_EXPLICIT_SCHED);    }    // CPU 亲和性属性设置,使用 cpuset(0,1)。    for (i = 0; i < THREAD_COUNT; ++i)    {        pthread_create(&pth[i], &attr[i], thread_func, (void *)i);        CPU_ZERO(&cpuset);        cpuid = i % 2;        CPU_SET(cpuid, &cpuset);        pthread_setaffinity_np(pth[i], sizeof(cpu_set_t), &cpuset);    }    for (i = 0; i < THREAD_COUNT; ++i)        pthread_join(pth[i], NULL);    // 清理线程属性    for (i = 0; i < THREAD_COUNT; ++i)        pthread_attr_destroy(&attr[i]);    return 0;}
  • CPU 调度亲和性效果。
    在这里插入图片描述

  • User Thread 和 LWP(12 + 1)绑定关系与调度策略效果。

$ ps -eLo pid,ppid,tid,lwp,nlwp,class,rtprio,ni,pri,psr,pcpu,policy,stat,comm | awk '$7 !~ /-/{print $0}'  PID  PPID   TID   LWP NLWP CLS RTPRIO  NI PRI PSR %CPU POL STAT COMMAND26031 24641 26032 26032   13 FF      10   -  50   0  0.0 FF  Rl+  test126031 24641 26033 26033   13 FF      10   -  50   1  0.0 FF  Rl+  test126031 24641 26034 26034   13 FF      10   -  50   0  0.0 FF  Rl+  test126031 24641 26035 26035   13 FF      10   -  50   1  0.0 FF  Rl+  test126031 24641 26036 26036   13 FF      10   -  50   0  0.0 FF  Rl+  test126031 24641 26037 26037   13 FF      10   -  50   1  0.0 FF  Rl+  test126031 24641 26038 26038   13 RR      20   -  60   0 33.3 RR  Rl+  test126031 24641 26039 26039   13 RR      20   -  60   1 33.3 RR  Rl+  test126031 24641 26040 26040   13 RR      20   -  60   0 33.3 RR  Rl+  test126031 24641 26041 26041   13 RR      20   -  60   1 33.2 RR  Rl+  test126031 24641 26042 26042   13 RR      20   -  60   0 33.2 RR  Rl+  test126031 24641 26043 26043   13 RR      20   -  60   1 33.3 RR  Rl+  test1
  • PID:进程 ID,唯一标识一个进程。
  • PPID:父进程 ID,标识当前进程的父进程。
  • TID:线程 ID,标识一个线程,与 LWP ID 一致(一一对应)。
  • LWP:LWP ID,是内核调度实体,多个 LWP 可以属于同一个进程,但它们的调度是相互独立的。
  • NLWP:进程的 LWP 数。
  • CLS:调度算法。
  • RTPRIO:实时优先级,仅适用于实时调度策略。
  • NI:Nice 值,越小表示越高的优先级。
  • PRI:优先级,与 NI 的值相关。
  • PSR:进程或线程所绑定的处理器编号。
  • %CPU:进程或线程的 CPU 使用率。
  • POL:进程或线程的调度策略。
  • STAT:进程或线程的状态。
  • COMMAND:进程或线程的命令名或可执行文件名。

多线程安全与多线程同步

多线程安全(Multi-Thread Safe),就是在多线程环境中,多个线程在同一时刻对同一份共享数据(Shared Resource,e.g. 寄存器、内存空间、全局变量、静态变量 etc.)进行写操作(读操作不会涉及线程安全的问题)时,不会出现数据不一致。

为了确保在多线程安全,就要确保数据的一致性,即:线程安全检查。多线程之间通过需要进行同步通信,以此来保证共享数据的一致性。

pthread 库提供了保证线程安全的方式:

  1. 互斥锁(Mutex):是一种线程安全机制,为共享数据加上一把锁,拥有锁的线程,才可以访问共享数据。以此保护共享数据不被多个线程同时访问。
  2. 条件变量(Condition Variable):是一种线程同步机制,用于判断线程是否满足了特定的竞争条件(Race Condition)。只有满足条件的线程,才可以获得互斥锁,以此来避免死锁的情况。

需要注意的是,线程安全检查的实现会带来一定的系统开销。

在这里插入图片描述

互斥锁(Mutex)

pthread_mutex_init()

函数作用:用于初始化一个互斥锁实体。

函数原型

  • mutex 参数:pthread_mutex_t 类型指针,用于指定要初始化的互斥锁。
  • attr 参数:pthread_mutexattr_t 类型指针,用于指定互斥锁的属性,例如:递归锁、非递归锁等,通常为 NULL。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

pthread_mutex_lock()

函数作用:User Thread 用于获取互斥锁。如果互斥锁已被 Other User Thread 获得,则当前 User Thread 会阻塞。

函数原型

  • mutex 参数:pthread_mutex_t 类型指针,用于指定要获取的互斥锁。
int pthread_mutex_lock(pthread_mutex_t *mutex);

pthread_mutex_unlock()

函数作用:User Thread 用于释放互斥锁,互斥锁重回可用状态。如果当前 User Thread 并没有锁,则该函数可能会产生未定义行为。

函数原型

  • mutex 参数:pthread_mutex_t 类型指针,用于指定要释放的互斥锁。
int pthread_mutex_unlock(pthread_mutex_t *mutex);

条件变量(Condition Variable)

互斥锁和条件变量都是多线程同步的工具,但是它们的作用不同:

  • 互斥:互斥锁可以保护共享资源的访问,防止多个线程同时修改共享资源,但是它无法告知其他线程何时可以安全地访问共享资源,有可能导致死锁的发生。

举例来说,存在全局变量 n(共享数据)被多线程访问。当 TA 获得锁后,在临界区中访问 n,且只有当 n > 0 时,才会释放锁。这意味着当 n == 0 时,TA 将永远不会释放锁,从而造成死锁。

在这里插入图片描述

那么解决死锁的方法,就是设定一个条件:只有当 n > 时,TA 才可以获得锁。而这个条件,就是多线程之间需要同步的信息。即:在多线程环境中,当一个线程需要等待某个条件成立时,才可以获得锁,那么应该使用条件变量来实现。

  • 同步:pthread 条件变量提供了一种线程同步机制,当特定的事件发生时,它可以唤醒一个或多个在等待事件的线程,从而实现线程间的同步和协调。条件变量通常与互斥锁一起使用,以避免竞态条件和死锁的发生。

pthread_cond_init()

函数作用:用于初始化一个条件变量实体。

函数原型

  • cond 参数:pthread_cond_t 类型指针,用于指定要初始化的条件变量。
  • attr 参数:pthread_condattr_t 类型指针,用于指定条件变量的属性,通常为 NULL。
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

pthread_cond_wait()

函数作用:线程用于等待某个条件变量满足。

  1. 当 T1 线程调用 pthread_cond_wait() 时,会自动地释放掉互斥锁,并阻塞线程,开始等待。
  2. 直到另一个 T2 线程调用了 pthread_cond_signal() 或 pthread_cond_broadcast(),以此来通知 T1 条件变量满足了。
  3. 然后 T1 pthread_cond_wait() 重新获取指定的互斥锁并返回。

在这里插入图片描述

函数原型

  • cond 参数:pthread_cond_t 类型指针,用于指定要等待的条件变量。
  • mutex 参数:pthread_mutex_t 类型指针,用于指定要关联的互斥锁。在等待期间,线程将释放该互斥锁。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

pthread_cond_signal()

函数作用:用于向等待条件变量的线程发送信号,唤醒其中的一个线程。

函数原型

  • cond 参数:pthread_cond_t 类型指针,用于指定要发送信号的条件变量。
int pthread_cond_signal(pthread_cond_t *cond);

pthread_cond_broadcast()

函数作用:用于向等待条件变量的所有线程发送信号,唤醒所有等待的线程。

函数原型

  • cond 参数:pthread_cond_t 类型指针,用于指定要发送信号的条件变量。
int pthread_cond_broadcast(pthread_cond_t *cond);

互斥锁和条件变量配合使用

当一个线程需要某个条件成立后才可以访问共享数据时。需要先锁定一个互斥锁,然后检查条件变量,如果条件不满足,则需要挂起并等待。

在这里插入图片描述

在这里插入图片描述

#include pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int data = 0;  // 共享数据void *producer(void *arg){    for (int i = 0; i < 10; i++) {        pthread_mutex_lock(&mutex); // 加锁        data++; // 修改共享数据        pthread_cond_signal(&cond); // 发送信号        pthread_mutex_unlock(&mutex); // 解锁        sleep(1);    }    pthread_exit(NULL);}void *consumer(void *arg){    while (1) {        pthread_mutex_lock(&mutex); // 加锁        while (data == 0) { // 如果没有数据就等待信号            pthread_cond_wait(&cond, &mutex);        }        printf("data = %d\n", data); // 打印共享数据        data--; // 修改共享数据        pthread_mutex_unlock(&mutex); // 解锁        sleep(1);    }    pthread_exit(NULL);}int main(){    pthread_t tid1, tid2;    pthread_create(&tid1, NULL, producer, NULL);    pthread_create(&tid2, NULL, consumer, NULL);    pthread_join(tid1, NULL);    pthread_join(tid2, NULL);    return 0;}

线程非安全标准库函数

C 语言提供的大部分标准库函数都是线程安全的,但是也有几个常用函数是线程不安全的,也称为不可重入函数,原因是使用了某些全局或者静态变量。

我们知道,全局变量和静态变量分别对应内存中的全局变量区和静态存储区,这些区域都是可以跨线程访问的。在多线程环境中,这些数据如果在没有加锁的情况下并行读写,就会造成 Segmentfault / CoreDump 之类的问题。

  • 不可重入函数汇总:
    在这里插入图片描述

来源地址:https://blog.csdn.net/Jmilk/article/details/129473253

--结束END--

本文标题: C 语言编程 — pthread 用户线程操作

本文链接: https://lsjlt.com/news/402619.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C 语言编程 — pthread 用户线程操作
    目录 文章目录 目录pthread 线程库TCB 结构体线程的生命周期管理线程的合并与分离pthread_create() 创建线程pthread_join() 合并线程pthread_exi...
    99+
    2023-09-10
    c语言 java jvm
  • C语言多线程pthread库的相关函数有哪些
    C语言多线程pthread库的相关函数有以下几个:1. pthread_create():创建一个新的线程。2. pthread_j...
    99+
    2023-08-18
    C语言 pthread
  • c语言线程编程是什么(c中线程的使用)
    C语言线程编程是指在C语言中使用多线程技术,通过创建和管理多个线程来实现并发执行的程序。在C语言中,可以使用线程库(如pthread...
    99+
    2023-09-22
    c语言
  • 关于C语言多线程pthread库的相关函数说明
    pthread库是C语言中用于多线程编程的一个标准库,包含了一系列的函数,用于创建、控制和管理线程。下面是一些常用的pthread库...
    99+
    2023-08-17
    C语言
  • 详解C语言编程之thread多线程
    目录线程创建与结束线程的创建方式:线程的结束方式:join()detach()互斥锁<mutex> 头文件介绍std::mutex 介绍std::lock_guardst...
    99+
    2024-04-02
  • C语言编程开发中位操作符有哪些
    本篇内容主要讲解“C语言编程开发中位操作符有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C语言编程开发中位操作符有哪些”吧!在C语言编程中,数据的位是可以操作的最小数据单位,理论上可以用“...
    99+
    2023-06-17
  • C语言编程C++旋转字符操作串示例详解
    目录旋转字符串字符串左旋题前认知:暴力移位:三步翻转:判断字符串旋转题前认知字符串追加判断旋转字符串 字符串左旋 实现一个函数,可以左旋字符串中的k个字符。 例如: ABCD左旋一个...
    99+
    2024-04-02
  • C语言编程C++编辑器及调试工具操作命令详解
    目录一、GCC编译器1、GNU工具2、GCC简介3、GCC编译器的版本4、gcc所支持后缀名解释5、编译器的主要组件6、GCC的基本用法和选项7、GCC的错误类型及对策8、GCC编译...
    99+
    2024-04-02
  • 易语言编程命令调用操作大全
    目录一、 命令概述二、 命令的格式三、 命令的参数四、 命令的返回值五、 命令嵌套调用六、 数组参数与数组返回值七、 流程控制类命令八、 算术运算命令九、 逻辑比较十、 位运算命令十...
    99+
    2024-04-02
  • c#编程语言用什么软件编程
    用于 c# 编程的流行软件有:microsoft visual studio:全面且最常用的 ide,提供完善的工具集。jetbrains rider:跨平台 ide,提供智能代码辅助和...
    99+
    2024-04-04
    linux macos c# 移动应用程序
  • c语言多线程怎么用
    c 语言中多线程的使用是指一种计算机技术,允许一个程序同时执行多个任务。具体实现步骤包括:1. 创建线程;2. 定义线程函数;3. 加入线程;4. 取消线程。为了确保线程安全地访问共享数...
    99+
    2024-05-15
    c语言 并发访问 同步机制
  • C语言编程中的thread多线程是怎样的
    本篇文章为大家展示了C语言编程中的thread多线程是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。线程创建与结束C++11 新标准中引入了四个头文件来支持多线程编程,他们分别是<ato...
    99+
    2023-06-21
  • python编程语言在操作文件编码格式的应用过程
    这期内容当中小编将会给大家带来有关python编程语言在操作文件编码格式的应用过程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。建立一个文件test.txt,文件格式用ANSI,内容为:abc中文用pyt...
    99+
    2023-06-17
  • 易语言编程命令调用操作有哪些
    这篇文章主要介绍了易语言编程命令调用操作有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、 命令概述     什么是命...
    99+
    2023-06-25
  • C语言*与&在操作线性表的作用详解
    在数据结构线性表一章,对线性表有这些操作方法(Operation): Initlist(*L); ListEmpty(L); ClearList(*L); G...
    99+
    2024-04-02
  • c语言是什么编程语言
    c语言作为一种通用、结构化的编程语言,自诞生以来广泛应用于计算机领域。其基本特性包括结构化编程、过程式编程、底层访问能力、高效性能和跨平台性。在编程语言中,c语言是系统级编程的基石,也是...
    99+
    2024-03-14
    c语言 网络编程 作用域
  • c语言怎么调用多线程
    在C语言中,可以使用线程库来调用多线程。C语言标准库并不直接提供多线程支持,但是你可以使用第三方库如POSIX threads(pt...
    99+
    2023-09-15
    c语言
  • c语言怎么使用多线程
    什么是多线程?多线程是一种并发编程技术,允许程序同时执行多个任务或线程。c 语言使用 posix 线程库创建和管理线程,步骤如下:创建线程加入线程线程函数同步(使用互斥锁、条件变量和信号...
    99+
    2024-05-21
    c语言 并发访问 同步机制
  • 操作系统:用户级线程与内核级线程之争
    操作系统中的线程可以分为用户级线程和内核级线程,各有利弊。用户级线程的创建和切换开销更小,并且不需要内核的支持,内核级线程的性能更好,但是创建和切换开销更大。 用户级线程 用户级线程是由用户空间的程序创建和管理的,不需要内核的支持。用户...
    99+
    2024-02-06
    操作系统 线程 用户级线程 内核级线程
  • 用户级线程 VS 内核级线程:操作系统中的线程之争
    在操作系统中,线程是一种轻量级进程,它与进程共享相同地址空间。用户级线程和内核级线程是两种不同的线程实现机制,各有优缺点。 用户级线程 定义:由用户空间的程序或库来管理和调度。 优点: 创建和销毁线程的速度快。 不需要内核参与,因此开销...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作