如何在 Linux 中创建线程
在本文中,我们将重点介绍如何创建和识别线程。我们还将提供一个有效的 C 程序示例,该示例将解释如何进行基本的线程编程。
线程识别
正如通过进程 ID 标识进程一样,线程也由线程 ID 标识。但有趣的是,两者的相似之处就到此为止了。
- 进程 ID 在整个系统中是唯一的,而线程 ID 仅在单个进程的上下文中是唯一的。
- 进程 ID 是整数值,但线程 ID 不一定是整数值。它很可能是一个结构
- 进程 ID 可以很容易地打印,而线程 ID 则不容易打印。
以上几点给出了关于进程 ID 和线程 ID 之间差异的概念。
线程 ID 由类型“pthread_t”表示。正如我们已经讨论过的,在大多数情况下,这种类型是一种结构,因此必须有一个可以比较两个线程 ID 的函数。
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);
如您所见,上述函数采用两个线程 ID,如果两个线程 ID 相等则返回非零值,否则返回零。
当一个线程想要知道它自己的线程 ID 时,可能会出现另一种情况。对于这种情况,以下函数提供所需的服务。
#include <pthread.h>
pthread_t pthread_self(void);
所以我们看到函数'pthread_self()'被一个线程用来打印它自己的线程ID。
现在,有人会问需要上述两个功能的情况。假设有一个链接列表包含不同线程的数据的情况。列表中的每个节点都包含一个线程 ID 和相应的数据。现在每当一个线程试图从链表中获取它的数据时,它首先通过调用'pthread_self()'来获取它自己的ID,然后它在每个节点上调用'pthread_equal()'来查看该节点是否包含它的数据.
上面讨论的一般情况的一个示例是主线程获取要处理的作业,然后将它们推送到链接列表中。现在各个工作线程解析链表并提取分配给它们的作业。
线程创建
通常,当程序启动并成为进程时,它会从默认线程开始。所以我们可以说每个进程至少有一个控制线程。进程可以使用以下函数创建额外的线程:
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg)
上面的函数需要四个参数,让我们先讨论一下它们:
- 第一个参数是 pthread_t 类型的地址。一旦函数调用成功,其地址作为第一个参数传递的变量将保存新创建线程的线程 ID。
- 第二个参数可能包含我们希望新线程包含的某些属性。它可能是优先级等。
- 第三个参数是函数指针。需要记住的是,每个线程都以一个函数开头,并且函数地址作为第三个参数在这里传递,以便内核知道从哪个函数开始线程。
- 由于函数(其地址在上面的第三个参数中传递)也可以接受一些参数,因此我们可以将这些参数以指向 void 类型的指针的形式传递。现在,为什么选择 void 类型?这是因为如果一个函数接受多个参数,那么这个指针可能是一个指向可能包含这些参数的结构的指针。
一个实用的线程示例
以下是我们尝试使用上面讨论的所有三个函数的示例代码。
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
pthread_t tid[2];
void* doSomeThing(void *arg)
{
unsigned long i = 0;
pthread_t id = pthread_self();
if(pthread_equal(id,tid[0]))
{
printf("\n First thread processing\n");
}
else
{
printf("\n Second thread processing\n");
}
for(i=0; i<(0xFFFFFFFF);i++);
return NULL;
}
int main(void)
{
int i = 0;
int err;
while(i < 2)
{
err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
else
printf("\n Thread created successfully\n");
i++;
}
sleep(5);
return 0;
}
所以这段代码的作用是:
- 它使用 pthread_create() 函数创建两个线程
- 两个线程的启动功能保持不变。
- 在函数 'doSomeThing()' 内部,线程使用 pthread_self() 和 pthread_equal() 函数来识别正在执行的线程是创建时的第一个线程还是第二个线程。
- 此外,在同一个函数 'doSomeThing()' 中运行一个 for 循环,以模拟一些耗时的工作。
现在,当上面的代码运行时,输出如下:
$ ./threads
Thread created successfully
First thread processing
Thread created successfully
Second thread processing
如输出所示,创建第一个线程并开始处理,然后创建第二个线程并开始处理。这里要注意的一点是线程的执行顺序并不总是固定的。这取决于操作系统的调度算法。
注意:本文中的全部解释都是在 Posix 线程上完成的。从类型中可以理解,pthread_t 类型代表 POSIX 线程。如果应用程序想要测试是否支持 POSIX 线程,则应用程序可以使用宏 _POSIX_THREADS 进行编译时测试。要编译包含对 posix API 的调用的代码,请使用编译选项“-pthread”。
- 点赞
- 收藏
- 关注作者
评论(0)