Linux中进程如何创建线程 (linux 进程中创建线程)

在Linux中,进程是计算机程序的基本执行单元,而线程是进程内部的并发执行流。线程能够共享进程的资源,如内存空间、文件句柄等。在这种情况下,它们可以协同工作,以便高效地完成任务。

尽管Linux内核直接支持多线程应用程序,但创建一个线程并不是容易的。许多程序员对它感到困惑,因为Linux中线程的实际实现可能与其他操作系统不同。在本文中,我们将介绍Linux中创建线程的方法,以及如何在程序中正确使用它们。

Linux中的线程是什么?

在Linux中,线程是一种轻量级的进程。每个线程都有自己的栈空间,但与进程不同,它们共享相同的地址空间。这意味着,线程能够访问相同的变量、函数以及文件等,从而可以在处理相同的数据时协作工作。

一个进程创建的线程被称为子线程,它们运行在相同的上下文中,但它们有自己的堆栈。进程本身也有一个主线程,它是之一个线程,它在进程初始化时自动创建。

Linux中创建线程的方法

在Linux中,应用程序可以使用线程API创建线程。常见的API包括pthread_create()和clone()。

pthread_create()

pthread_create()是一个库函数,允许我们在进程中创建多个线程。它可以创建一个新的线程,并附加到进程中。它的语法如下:

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

此函数的之一个参数为线程标识符pthread_t,它是一个变量,用于存储创建的线程的唯一标识符。第二个参数为线程的属性,我们通常将其设置为NULL。第三个参数是一个指向函数的指针,该函数是新线程的开始函数。第四个参数是该函数的参数,传递给线程函数的参数。

以下是使用pthread_create()函数创建并启动一个简单线程的示例:

#include

#include

void *print_message_function( void *ptr );

int mn()

{

pthread_t thread1, thread2;

char *message1 = “Thread 1”;

char *message2 = “Thread 2”;

int iret1, iret2;

// 创建线程1

iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);

// 创建线程2

iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);

// 等待线程1执行完

pthread_join( thread1, NULL);

// 等待线程2执行完

pthread_join( thread2, NULL);

printf(“Thread 1 returns: %d\n”,iret1);

printf(“Thread 2 returns: %d\n”,iret2);

}

void *print_message_function( void *ptr )

{

char *message;

message = (char *) ptr;

printf(“%s \n”, message);

}

在上述代码中,我们创建了两个线程thread1和thread2,并分别将它们赋值为参数。然后,使用pthread_create()函数创建线程,并将线程函数指针和参数传递给函数。然后,我们等待线程执行完,并检查线程返回的值。

clone()

另一个创建线程的函数是clone()。它类似于pthread_create(),但它更为底层。clone()函数必须显式提供线程栈和堆栈的空间。以下是一个使用clone()函数创建线程的示例:

#define _GNU_SOURCE /* 包含clone()函数 */

#include

#include

#define STACK_SIZE 1024*1024

static char child_stack[STACK_SIZE];

void* child_fn(void* arg)

{

printf(“Child %ld running in new namespace\n”, (long)getpid());

return NULL;

}

int mn()

{

pid_t child_pid = clone(child_fn,child_stack+STACK_SIZE,SIGCHLD,NULL);

printf(“clone()=%ld\n”, (long)child_pid);

getchar(); /* 继续运行以查看输出结果 */

return 0;

}

在上述代码中,我们使用了clone()函数来创建新的进程,并将创建的新进程的地址存储在变量child_pid中。线程函数为child_fn()。

线程常见问题

创建线程时有许多问题,包括如何同步线程、如何处理线程处理的异常,如何避免线程之间的竞争等。以下是一些常见的线程问题:

线程同步

线程同步是一个重要的问题,因为如果多个线程同时访问共享资源,会出现数据不一致的问题。因此,使用线程同步技术来协调并发线程非常重要,以避免这种冲突。线程同步包括锁、条件变量和信号量等。

线程异常

当线程中的一个操作无法执行时,例如分配内存失败或输入格式不正确时,线程将返回异常。这时,应该为线程实现一个错误处理功能,以便在发生异常时能够及时处理错误信息。

线程竞争

如果两个或更多线程在同一时间访问同一数据,就会发生竞争。这可能导致数据丢失,死锁和其他问题。线程竞争可以通过正确实现线程同步来避免。

结论

相关问题拓展阅读:

linux进程、线程及调度算法(三)

调度策略值得是大家都在ready时,并且CPU已经被调度时,决定谁来运行,谁来被调度。

两者之间有一定矛盾。

响应的优化,意味着高优先级会抢占优先级,会花时间在上下文切换,会影响吞吐。

上下文切换的时间是很短的,几微妙就能搞定。上下文切换本身对吞吐并多大影响,

重要的是,切换后引起的cpu 的 cache miss.

每次切换APP, 数据都要重新load一次。

Linux 会尽可能的在响应与吞吐之间寻找平衡。比如在编译linux的时候,会让你选择 kernal features -> Preemption model.

抢占模型会影响linux的调度算法。

所以 ARM 的架构都是big+LITTLE, 一个很猛CPU+ 多个 性能较差的 CPU, 那么可以把I/O型任务的调度指源 放在 LITTLE CPU上。需要计算的放在big上。

早期2.6 内核将优先级划分了bit的优先级。数值越低,优先级越高。0-99优先级 都是 RT(即时响应)的 ,都是非RT的,即normal。

调度的时候 看哪个bitmap 中的 优先级上有任务ready。可能多个任务哦。

在普通优先级线程调度中,高优先级并不代表对低优先级的绝对优势。会在不同优先级进行轮转。

就是比101高,101也会比102高,但100 不会堵着101。

众丝进程在轮转时,优先级高的:

初始唯并态设置nice值为0,linux 会探测 你是喜欢睡眠,还是干活。越喜欢睡,linux 越奖励你,优先级上升(nice值减少)。越喜欢干活,优先级下降(nice值增加)。所以一个进程在linux中,干着干着 优先级越低,睡着睡着 优先级越高。

后期linux补丁中

红黑树,数据结构, 左边节点小于右边节点

同时兼顾了 CPU/IO 和 nice。

数值代表着 进程运行到目前为止的virtual runtime 时间。

(pyhsical runtime) / weight * 1024(系数)。

优先调度 节点值(vruntime)最小的线程。权重weight 其实有nice 来控制。

一个线程一旦被调度到,则物理运行时间增加,vruntime增加,往左边走。

weight的增加,也导致vruntime减小,往右边走。

总之 CFS让线程 从左滚到右,从右滚到左。即照顾了I/O(喜欢睡,分子小) 也 照顾了 nice值低(分母高).所以 由喜欢睡,nice值又低的线程,最容易被调度到。

自动调整,无需向nice一样做出奖励惩罚动作,个人理解权重其实相当于nice

但是 此时 来蔽拍一个 0-99的线程,进行RT调度,都可以瞬间秒杀你!因为人家不是普通的,是RT的!

一个多线程的进程中,每个线程的调度的策略 如 fifo rr normal, 都可以不同。每一个的优先级都可以不一样。

实验举例, 创建2个线程,同时开2个:

运行2次,创建两个进程

sudo renice -n -5(nice -5级别) -g(global), 会明显看到 一个进程的CPU占用率是另一个的 3倍。

为什么cpu都已经达到200%,为什么系统不觉得卡呢?因为,我们的线程在未设置优先级时,是normal调度模式,且是

CPU消耗型

调度级别其实不高。

利用chrt工具,可以将进程 调整为 50 从normal的调度策略 升为RT (fifo)级别的调度策略,会出现:

chrt , nice renice 的调度策略 都是以线程为单位的,以上 设置的将进程下的所有线程进行设置nice值

线程是调度单位,进程不是,进程是资源封装单位!

两个同样死循环的normal优先级线程,其中一个nice值降低,该线程的CPU 利用率就会比另一个CPU的利用率高。

关于linux 进程中创建线程的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » Linux中进程如何创建线程 (linux 进程中创建线程)