当前位置: 首页 > wzjs >正文

好的品牌设计网站有哪些百度手机浏览器

好的品牌设计网站有哪些,百度手机浏览器,网页设计师可转行培训,wordpress 12张表目录 一、POSIX线程库简介 二、线程创建 2.1 单线程创建示例 2.2 多线程创建示例 2.3 线程ID的获取与使用 2.4 线程与进程的关系 2.5 线程的调度与LWP 三、线程等待 1. 为什么需要线程等待? 2. 线程等待实例 2.1 基本线程等待 2.2 获取线程退出码 3. 线…

目录

一、POSIX线程库简介

二、线程创建

2.1 单线程创建示例

2.2 多线程创建示例

2.3 线程ID的获取与使用

2.4 线程与进程的关系

2.5 线程的调度与LWP

三、线程等待 

1. 为什么需要线程等待?

2. 线程等待实例

2.1 基本线程等待

2.2 获取线程退出码

3. 线程异常终止的影响

四、线程终止

1. 线程终止的三种方式

2. return:线程的自然结束

3. pthread_exit:线程的主动谢幕

4. pthread_cancel:线程的强制终止

五、分离线程

1. 什么是分离线程?

2. 自动分离线程

3. 分离线程的优势

4. 注意事项

六、线程ID与进程地址空间布局

1. 线程ID的双重身份

1.1 操作系统调度器的线程ID

1.2 NPTL线程库的线程ID

2. 线程ID的存储与管理

2.1 线程控制块(struct pthread)

2.2 线程栈与资源

3. 进程地址空间布局


一、POSIX线程库简介

        POSIX线程库是一组标准化的线程接口,几乎所有支持POSIX标准的系统(比如Linux、macOS)都内置了对它的支持。它的核心函数都以 pthread_ 开头,使用时需要包含头文件<pthread.h>,并在编译时加上 -lpthread 选项。

        线程是进程中的一个执行单元,多个线程共享同一进程的资源(比如内存、文件描述符等),但它们可以独立运行。线程的轻量化特性使得它在处理并发任务时比进程更加高效。

二、线程创建

创建线程的核心函数是 pthread_create,它的原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);
  • thread:用于存储新创建线程的ID。

  • attr:线程属性(比如栈大小、优先级等),通常传NULL表示使用默认属性。

  • start_routine:线程启动后执行的函数地址。

  • arg:传递给启动函数的参数。

  • 线程创建成功返回0,失败返回错误码。

2.1 单线程创建示例

我们先从最简单的例子开始:主线程创建一个新线程。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>// 线程执行的函数
void* thread_function(void* arg) 
{char* msg = (char*)arg;while (1) {printf("I am %s\n", msg); // 打印线程信息sleep(1); // 模拟任务执行}return NULL; // 线程结束
}int main() 
{pthread_t tid; // 存储线程IDpthread_create(&tid, NULL, thread_function, (void*)"thread 1"); // 创建线程while (1) {printf("I am main thread!\n"); // 主线程任务sleep(2);}return 0;
}

        运行后,你会看到主线程和新线程交替打印信息。新线程每秒打印一次,而主线程每两秒打印一次。

        当我们用 ps axj 命令查看当前进程的信息时,虽然此时该进程中有两个线程,但是我们看到的进程只有一个,因为这两个线程都是属于同一个进程的。 

2.2 多线程创建示例

如果我们想创建多个线程,可以稍微修改代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>void* thread_function(void* arg) 
{char* msg = (char*)arg;while (1) {printf("I am %s...tid: %lu\n", msg, getpid()); // 打印线程IDsleep(1);}return NULL;
}int main()
{pthread_t threads[5]; // 存储5个线程IDfor (int i = 0; i < 5; i++) {char* msg = (char*)malloc(64);sprintf(msg, "thread %d", i); // 动态生成线程名称pthread_create(&threads[i], NULL, thread_function, msg);}while (1) {printf("I am main thread...tid: %lu\n", getpid()); // 主线程IDsleep(2);}return 0;
}

运行后,你会看到5个新线程和主线程同时运行,主线程和新线程的PID是一样的,也就是说主线程和新线程虽然是两个执行流,但它们仍然属于同一个进程。

2.3 线程ID的获取与使用

线程ID是区分线程的重要标识,获取方式有两种:

  1. 创建线程时通过输出型参数获取:这是pthread_create的默认行为。

  2. 调用pthread_self函数:返回当前线程的ID。

pthread_t pthread_self(void);

代码示例: 

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>  // 用于 sleep 函数// 线程函数
void* thread_function(void* arg) 
{// 获取当前线程的 IDpthread_t tid = pthread_self();// 将 pthread_t 转换为 unsigned long 以便打印printf("子线程 ID: %lu\n", (unsigned long)tid);sleep(1);return NULL;
}int main() 
{pthread_t thread_id;// 创建一个新线程if (pthread_create(&thread_id, NULL, thread_function, NULL) != 0) {perror("线程创建失败");return 1;}// 主线程中打印自己的线程 IDprintf("主线程 ID: %lu\n", (unsigned long)pthread_self());return 0;
}

2.4 线程与进程的关系

        线程是进程中的一个执行单元,多个线程共享同一进程的资源。我们可以通过getpidgetppid函数验证这一点:

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void* thread_function(void* arg) 
{char* msg = (char*)arg;while (1) {printf("I am %s...pid: %d, ppid: %d\n", msg, getpid(), getppid());sleep(1);}return NULL;
}int main() 
{pthread_t tid;pthread_create(&tid, NULL, thread_function, (void*)"thread 1");while (1) {printf("I am main thread...pid: %d, ppid: %d\n", getpid(), getppid());sleep(2);}return 0;
}

运行后,你会发现主线程和新线程的pidppid完全相同,这说明它们属于同一个进程。

2.5 线程的调度与LWP

        在Linux中,线程实际上是通过内核的轻量级进程(LWP)实现的。每个线程都有一个对应的LWP,而LWP才是操作系统调度的最小单位。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>#define NUM_THREADS 3// 线程函数:打印线程 ID
void *thread_task(void *arg)
{int thread_id = *(int *)arg;for (int i = 0; i < 3; i++){printf("线程 %d (pthread_t: %lu) - 执行次数: %d\n",thread_id, (unsigned long)pthread_self(), i);sleep(1);}return NULL;
}int main()
{pthread_t threads[NUM_THREADS];int thread_args[NUM_THREADS];// 创建多个线程for (int i = 0; i < NUM_THREADS; i++){thread_args[i] = i;pthread_create(&threads[i], NULL, thread_task, &thread_args[i]);}// 主线程也打印自己的线程 IDprintf("主线程 ID: %lu\n", (unsigned long)pthread_self());// 等待所有子线程结束for (int i = 0; i < NUM_THREADS; i++){pthread_join(threads[i], NULL);}return 0;
}

我们可以通过ps -aL命令查看线程的LWP信息:

运行上面的命令,你会看到每个线程的LWP ID,以及它们所属的进程ID(PID)。

三、线程等待 

1. 为什么需要线程等待?

        线程被创建后,就像进程一样,它的资源需要被回收。如果不等待线程结束,这些资源就会变成“僵尸”,导致内存泄漏。就像餐厅的服务员完成任务后,经理需要确认他们已经下班,否则餐厅的运营效率会受到影响。

线程等待的核心函数是 thread_join,它的原型如下:

int pthread_join(pthread_t thread, void **retval);
  • thread:需要等待的线程ID。

  • retval:存储线程退出时的返回值。

  • 返回值:成功返回0,失败返回错误码。

调用pthread_join的线程会挂起,直到目标线程结束。

2. 线程等待实例

2.1 基本线程等待

我们先来看一个简单的例子,主线程创建5个新线程,并等待它们完成。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// 线程执行函数
void *thread_function(void *arg)
{char *msg = (char *)arg;int count = 0;while (count < 5){printf("I am %s...tid: %lu\n", msg, pthread_self());sleep(1);count++;}return NULL; // 正常退出
}int main()
{pthread_t threads[5]; // 存储5个线程IDfor (int i = 0; i < 5; i++){char *msg = (char *)malloc(64);sprintf(msg, "thread %d", i);pthread_create(&threads[i], NULL, thread_function, msg);}// 等待所有线程完成for (int i = 0; i < 5; i++){pthread_join(threads[i], NULL);printf("Thread %d[%lu]...done\n", i, threads[i]);}return 0;
}

运行后,你会看到每个线程打印5次信息,然后主线程依次等待它们完成。

2.2 获取线程退出码

线程退出时可以返回一个值,就像函数返回值一样。我们可以通过pthread_join获取这个值。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// 线程执行函数
void *thread_function(void *arg)
{char *msg = (char *)arg;int count = 0;while (count < 5){printf("I am %s...tid: %lu\n", msg, pthread_self());sleep(1);count++;}return (void *)2023; // 返回退出码
}int main()
{pthread_t threads[5];for (int i = 0; i < 5; i++){char *msg = (char *)malloc(64);sprintf(msg, "thread %d", i);pthread_create(&threads[i], NULL, thread_function, msg);}// 等待并获取退出码for (int i = 0; i < 5; i++){void *exit_code;pthread_join(threads[i], &exit_code);printf("Thread %d[%lu]...done, exit code: %d\n", i, threads[i], (int)exit_code);}return 0;
}

运行后,你会看到每个线程的退出码被成功捕获。

3. 线程异常终止的影响

        线程异常终止(比如崩溃)会导致整个进程崩溃。这是因为线程共享进程的资源,一个线程的崩溃会影响整个进程。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// 线程执行函数
void *thread_function(void *arg)
{char *msg = (char *)arg;int count = 0;while (count < 5){printf("I am %s...tid: %lu\n", msg, pthread_self());sleep(1);count++;int a = 1 / 0; // 故意制造错误}return NULL;
}int main()
{pthread_t threads[5];for (int i = 0; i < 5; i++){char *msg = (char *)malloc(64);sprintf(msg, "thread %d", i);pthread_create(&threads[i], NULL, thread_function, msg);}// 等待线程(可能永远不会到达这里)for (int i = 0; i < 5; i++){pthread_join(threads[i], NULL);}return 0;
}

运行这段代码,你会发现一旦某个线程崩溃,整个程序都会退出。这说明多线程程序的健壮性需要特别注意。

四、线程终止

1. 线程终止的三种方式

在POSIX线程库中,有三种方式可以终止线程:

  1. 从线程函数返回:就像函数执行完毕一样,线程自然结束。

  2. 调用pthread_exit:线程主动请求结束自己。

  3. 调用pthread_cancel:由其他线程强制终止某个线程。

2. return:线程的自然结束

核心原理:通过函数返回来结束线程执行流
特点

  • 主线程return会导致进程终止

  • 子线程return仅终止当前线程

void* worker(void* arg) {int count = 0;while(count++ < 3) {printf("子线程工作中...\n");sleep(1);}return NULL;  // 正常退出
}int main() {pthread_t tid;pthread_create(&tid, NULL, worker, NULL);// 主线程立即返回导致进程终止return 0;  // 错误示例!子线程来不及执行
}

执行现象:看不到任何输出,因为主线程退出导致进程终止 

3. pthread_exit:线程的主动谢幕

APIpthread_exit(void *retval)
特性

  • 可携带退出状态码

  • 退出码内存必须全局或堆分配

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>void* task(void* arg) 
{int* exit_code = malloc(sizeof(int));  // 必须堆分配*exit_code = 2023;for(int i=0; i<3; i++){printf("处理任务阶段%d\n", i+1);sleep(1);}pthread_exit(exit_code);  // 携带状态码退出
}int main() 
{pthread_t tid;void* ret_val;pthread_create(&tid, NULL, task, NULL);pthread_join(tid, &ret_val);printf("线程退出码:%d\n", *(int*)ret_val);free(ret_val);  // 记得释放堆内存return 0;
}

4. pthread_cancel:线程的强制终止

APIpthread_cancel(pthread_t thread)
重要特性

  • 异步终止可能引发资源泄漏

  • 被取消线程退出码为-1(PTHREAD_CANCELED)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// 线程执行函数
void *thread_function(void *arg)
{char *msg = (char *)arg;int count = 0;while (count < 5){printf("I am %s...tid: %lu\n", msg, pthread_self());sleep(1);count++;}pthread_exit((void *)2025);
}int main()
{pthread_t threads[5];for (int i = 0; i < 5; i++){char *msg = (char *)malloc(64);sprintf(msg, "thread %d", i);pthread_create(&threads[i], NULL, thread_function, msg);}// 取消前4个线程for (int i = 0; i < 4; i++){pthread_cancel(threads[i]);printf("Canceled thread %d[%lu]\n", i, threads[i]);}// 等待所有线程for (int i = 0; i < 5; i++){void *ret;pthread_join(threads[i], &ret);printf("Thread %d[%lu]...done, exit code: %d\n", i, threads[i], (int)ret);}return 0;
}

运行后,你会发现前4个线程被强制终止,退出码为-1,而第5个线程正常结束。

五、分离线程

1. 什么是分离线程?

        分离线程是一种特殊的线程状态,它告诉系统:当线程退出时,自动释放所有资源,无需手动调用pthread_join。就像快递员完成任务后直接离开,不需要快递公司再确认他是否完成任务。

分离线程的核心函数是pthread_detach,它的原型如下:

int pthread_detach(pthread_t thread);
  • thread:需要分离的线程ID。

  • 返回值:成功返回0,失败返回错误码。

分离线程后,线程的资源会在它退出时自动释放。一个线程不能同时是joinable和分离的。

2. 自动分离线程

我们可以通过pthread_detach将线程设置为分离状态。例如:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>// 线程执行函数
void *thread_function(void *arg)
{printf("%s\n", (char *)arg);    // 打印传入的消息pthread_detach(pthread_self()); // 将自己设置为分离线程return NULL;
}int main()
{pthread_t tid;if (pthread_create(&tid, NULL, thread_function, "Hello from detached thread!") != 0){printf("Failed to create thread\n");return 1;}// 等待一段时间,确保线程完成sleep(1);// 尝试等待线程(会失败,因为线程已经分离)if (pthread_join(tid, NULL) == 0){printf("Thread joined successfully\n");}else{printf("Failed to join thread (expected behavior for detached thread)\n");}return 0;
}

运行后,你会看到线程打印了消息,但pthread_join会失败,因为线程已经分离。

3. 分离线程的优势

分离线程非常适合以下场景:

  • 不关心线程返回值:比如后台日志记录线程,我们只需要它运行,不需要关心它的结果。

  • 简化代码:避免手动等待线程,减少代码复杂度。

4. 注意事项

  1. 分离线程无法被等待:一旦线程被分离,pthread_join将始终失败。

  2. 分离时机很重要:最好在主线程中等待一段时间,确保子线程完成分离操作。

  3. 资源自动释放:分离线程的资源会在它退出时自动释放,无需手动干预。

六、线程ID与进程地址空间布局

1. 线程ID的双重身份

1.1 操作系统调度器的线程ID

        线程是操作系统调度器的最小单位,每个线程都有一个由内核分配的唯一标识符,称为轻量级进程ID(LWP ID)。这个ID用于操作系统调度线程。

1.2 NPTL线程库的线程ID

        在Linux的NPTL(Native POSIX Thread Library)实现中,pthread_create函数生成的线程ID是线程库内部使用的标识符。它本质上是一个指向线程控制块(struct pthread)的地址。

pthread_t pthread_self(void);

pthread_t类型的线程ID是进程地址空间中的一个地址,指向线程的控制块。线程库通过这个地址来管理线程的生命周期。

2. 线程ID的存储与管理

2.1 线程控制块(struct pthread

        每个线程都有一个对应的控制块(struct pthread),它存储了线程的栈、局部存储等信息。pthread_t类型的线程ID实际上是指向这个控制块的地址。

2.2 线程栈与资源

        线程的栈和局部存储是线程运行时的核心资源。这些资源在进程的地址空间中分配,由线程库管理。

3. 进程地址空间布局

进程的地址空间由多个区域组成,包括内核空间、主线程栈、动态库、线程栈等。以下是具体布局:

  1. 内核空间:操作系统内核代码和数据。

  2. 主线程栈:主线程的栈空间。

  3. 动态库:加载的动态链接库。

  4. 线程控制块:每个线程的控制块。

  5. 线程栈:每个线程的栈空间。

  6. :动态分配的内存区域。

  7. 未初始化数据段:未初始化的全局变量。

  8. 已初始化数据段:已初始化的全局变量。

  9. 代码段:程序的可执行代码。 

http://www.dtcms.com/wzjs/206921.html

相关文章:

  • 网站开发职业认知小结国际热点新闻
  • uc网站模板成都百度业务员电话
  • 针对人群不同 网站做细分seo关键词排名教程
  • 做 淘宝客最大的网站是叫什么做seo网页价格
  • 乐清外贸网站建设推广方案的推广内容怎么写
  • 交互式网站建设百度关键字
  • 企业做网站的优势网站推广在线推广
  • wordpress网站维护页面模板视频号关键词搜索排名
  • 建设工程八大员考试网站搜索引擎营销简称seo
  • 网站建设需要注意哪些事项成都seo优化
  • 中国政府网站建设与应用国际十大市场营销公司
  • 企业品牌网站建设多少钱百度识图在线使用
  • 个人做网站犯法吗友情网站
  • 嘉善县建设局网站网络营销的5种方式
  • 青岛做公司网站注册的多吗黑科技引流软件是真的吗
  • 网站内容规划要包括什么内容百度搜索引擎竞价排名
  • b站推广首页网络推广策划
  • 宁夏银川做网站的公司广州网站优化公司排名
  • 东莞企业网站建设报价网站seo方案策划书
  • 怎么自己做网站推广成都网站seo服务
  • 泉州网站制作维护百度快速排名系统查询
  • 龙华民治网站建设公司搜索网站的浏览器
  • 住建部网站2015年城市建设统计服装店营销策划方案
  • 如何做网站的关键词排名爱站网官网
  • 大学里读网站建设九易建网站的建站模板
  • 做网站需要服务器吗百度推广排名代发
  • 宿州网站建设多少钱百度助手应用商店下载安装
  • 哪家网站设计公司好竞价托管优化公司
  • 建工教育网校官方网站企查查在线查询
  • 万业网网站建设审核云南疫情最新消息