POSIX线程通常被称为 PThreads 。它是一种独立于语言和并行执行模型的执行模型。它允许程序控制多个在时间上重叠的不同工作流。每个工作流称为一个 线程 。通过调用POSIX线程API来创建和控制这些流程。POSIX线程是由标准POSIX.1c(IEEE Std 1003.1c-1995)定义的API。
该API的实现在许多类Unix的POSIX兼容操作系统上可用,如FreeBSD、NetBSD、OpenBSD、Linux、macOS、Android、Solaris、Redox和AUTOSAR Adaptive,通常作为一个库 libPThread 提供。DR-DOS和Microsoft Windows实现也存在于SFU/SUA子系统中,该子系统提供了许多POSIX API的本机实现,以及第三方软件包中的 PThreads-w32 ,该软件包在现有的Windows API之上实现了 PThreads 。
PThreads是一个高度具体的多线程系统,是UNIX系统的默认标准。PThreads是POSIX线程的缩写,而POSIX是Portable Operating System Interface的缩写,它是操作系统必须实现的一种接口类型。POSIX中的PThreads概述了操作系统必须提供的线程API。
在多处理器或多核系统上,PThreads的工作效果很好,因为进程流可以被调度到另一个处理器上执行,通过并行或分布式处理提高速度,因为系统不会为进程创建一个新的系统、虚拟内存空间和环境,所以线程相对于forking或创建一个新进程的开销较小。
PThread头文件
要使用PThread接口,我们必须在CPP脚本的开头包含PThread.h头文件。
#include <PThread.h>
以下是解答为什么在操作系统中使用PThreads的原因:
PThreads定义了一组C编程语言类型、函数和常量。它使用了一个PThread.h头文件和一个线程库来实现。
大约有100个线程过程,都以PThread_为前缀,可以分为以下四组:
POSIX信号量API与POSIX线程一起工作,但它不是线程标准的一部分,而是在POSIX.1b、实时扩展(IEEE Std 1003.1b-1993)标准中定义的。因此,信号量过程的前缀为sem_而不是PThread_。下面是一个示例,说明了在C中使用PThreads:
#include
#include
#include
#include
#include
#define NUM_THREADS 5
void *perform_work(void *arguments)
{
int index = *((int *)arguments);
int sleep_time = 1 + rand() % NUM_THREADS;
printf("THREAD %d: Started.\n", index);
printf("THREAD %d: Will be sleeping for %d seconds.\n", index, sleep_time);
sleep(sleep_time);
printf("THREAD %d: Ended.\n", index);
return NULL;
}
int main(void)
{
PThread_t threads[NUM_THREADS];
int thread_args[NUM_THREADS];
int i;
int result_code;
//create all threads one by one
for (i = 0; i < NUM_THREADS; i++)
{
printf("IN MAIN: Creating thread %d.\n", i);
thread_args[i] = i;
result_code = PThread_create(&threads[i], NULL, perform_work, &thread_args[i]);
assert(!result_code);
}
printf("IN MAIN: All threads are created.\n");
//wait for each thread to complete
for (i = 0; i < NUM_THREADS; i++)
{
result_code = PThread_join(threads[i], NULL);
assert(!result_code);
printf("IN MAIN: Thread %d has ended.\n", i);
}
printf("MAIN program has ended.\n");
return 0;
}
上面的程序创建了五个线程,每个线程都执行函数 perform_work ,该函数将该线程的唯一编号打印到标准输出。如果程序员希望线程之间进行通信,这将需要在任何函数作用域之外定义一个变量,使其成为全局变量。可以使用 gcc 编译器编译这个程序,使用以下命令:
gcc PThreads_demo.c -PThread -o PThreads_demo
输出
这是运行此程序时的众多可能输出之一。
IN MAIN: Creating thread 0.
IN MAIN: Creating thread 1.
IN MAIN: Creating thread 2.
IN MAIN: Creating thread 3.
THREAD 0: Started.
IN MAIN: Creating thread 4.
THREAD 3: Started.
THREAD 2: Started.
THREAD 0: Will be sleeping for 3 seconds.
THREAD 1: Started.
THREAD 1: Will be sleeping for 5 seconds.
THREAD 2: Will be sleeping for 4 seconds.
THREAD 4: Started.
THREAD 4: Will be sleeping for 1 second.
IN MAIN: All threads are created.
THREAD 3: Will be sleeping for 4 seconds.
THREAD 4: Ended.
THREAD 0: Ended.
IN MAIN: Thread 0 has ended.
THREAD 2: Ended.
THREAD 3: Ended.
THREAD 1: Ended.
IN MAIN: Thread 1 has ended.
IN MAIN: Thread 2 has ended.
IN MAIN: Thread 3 has ended.
IN MAIN: Thread 4 has ended.
MAIN program has ended.
Windows不原生支持PThreads标准。因此PThreads4w项目致力于提供一个可移植且开源的包装实现。同时,它可以在不或只做少量修改的情况下,将使用PThreads的UNIX软件移植到Windows平台。
PThreads4w 3.0.0版本及更高版本,使用Apache Public License v2.0发布,兼容64位或32位的Windows系统。LGPLv3许可下的2.11.0版本,同样兼容64位或32位。
Mingw-w64项目还包含一个对PThreads和winPThreads的包装实现,使用比PThreads4w项目更多的原生系统调用。
Windows的Unix Services for UNIX/Subsystem for UNIX-based Applications软件包中也提供了一个PThreads API的本地移植版本,即不通过Win32/Win64 API映射,而是直接建立在操作系统的系统调用接口之上。
以下是PThreads中可用的扩展工具列表,例如:
参数指定的参数,并且将指定的 start_routine 函数作为其初始函数。创建的线程将在调用 PThread_create 后立即运行。
成功创建线程后,将保存线程标识符到 thread 参数指向的位置,并返回0。如果发生错误,返回相应的错误代码。
int PThread_join(PThread_t thread, void **value_ptr) ;
PThread_join子例程挂起调用线程,直到由thread参数指定的目标线程终止。如果目标线程已经终止,则子例程立即返回。可以显式地将目标线程分离以避免成为可连接的。
如果value_ptr参数不为NULL,则目标线程的退出状态将存储在其所指向的位置中。如果线程被取消,则退出状态将为PTHREAD_CANCELED。
void PThread_exit(void *value_ptr);
PThread_exit子例程终止调用线程,并将值value_ptr返回给调用PThread_join的任何其他线程。等待调用线程终止的任何线程都可以通过PThread_join子例程获取调用线程的退出状态。
一旦调用了PThread_exit子例程,调用线程将立即终止,并且不会返回给其调用者。
PThread_t PThread_self(void);
PThread_self子例程返回调用线程的线程标识符。
int PThread_cancel(PThread_t thread);
PThread_cancel子例程请求取消由thread参数指定的目标线程。如果线程仍可取消,则将异步取消它。子例程不会等待目标线程终止。
如果目标线程尚不可取消,则取消请求将延迟,直到目标线程进行取消点。
参数,并执行 start_routine 例程。参数 arg 是一个空指针,用于引用任何数据。
PThread_create 子例程通过线程参数返回新的线程标识符。调用者可以使用此线程标识符对线程执行各种操作。应检查此标识符,以确保成功创建了线程。
void PThread_exit(void *value_ptr);
PThread_exit 子例程安全地终止调用线程,并为任何可能加入调用线程的线程存储终止状态。
与退出子程序不同,PThread_exit子程序不关闭文件。因此,在调用此子程序之前,必须关闭由调用线程打开并仅由其使用的任何文件。从线程的初始例程返回会隐式调用PThread_exit子程序,使用返回值作为参数。
PThread_self 子程序返回调用线程的标识符。
int PThread_join: PThread_join子程序阻塞调用线程,直到在调用中指定的线程终止。目标线程的终止状态在status参数中返回。
int PThread_join(PThread_t thread, void **value_ptr);
如果目标线程已经终止但尚未分离,该子程序将立即返回。即使目标线程尚未终止,也无法加入已分离的线程。在所有已加入的线程被唤醒后,目标线程会自动分离。
该子程序本身不会导致线程终止。它类似于PThread_cond_wait子程序,用于等待特殊条件。
int PThread_detach(PThread_t thread, void **value_ptr);
The PThread_detach 子例程指示实现,当线程标识符位于位置 thread 时,可以在该线程终止时回收存储。无论线程是否已分离,此存储都将在进程退出时回收,可以包括线程返回值的存储。
如果一个线程尚未终止, PThread_detach 不会导致其终止。对同一目标线程的多次 PThread_detach 调用会导致错误。
如果目标线程已经终止但尚未分离,则子例程立即返回。即使未终止,也无法加入已分离的线程。在所有已加入的线程被唤醒后,目标线程会自动分离。它初始化一个互斥锁并设置其属性。
int PThread_mutex_init (PThread_mutex_t *mutex, PThread_mutexattr_t *attr);
PThread_mutex_init 子例程根据 mutex 属性对象 attr 初始化一个新的互斥锁并设置其属性。互斥锁最初为解锁状态。
初始化互斥锁后,互斥锁属性对象可以被重复使用用于另一个互斥锁初始化或删除。
被删除.
int PThread_mutex_destroy(PThread_mutex_t *mutex);
PThread_mutex_destroy 子程序删除互斥体。删除互斥体后,参数 mutex 无效,直到再次通过调用 PThread_mutex_init 子程序对其进行初始化为止。
int PThread_mutex_lock (PThread_mutex_t *mutex);
调用 PThread_mutex_lock 锁定由 mutex 引用的互斥体。如果互斥体已被锁定,则调用线程将被阻塞,直到互斥体可用为止。此操作返回通过 mutex 被调用的线程处于锁定状态。
int PThread_mutex_trylock(PThread_mutex_t *mutex);
函数 PThread_mutex_trylock 与 PThread_mutex_lock 的作用类似,只是如果互斥锁对象由mutex引用的当前被任何线程(包括当前线程)锁定,调用将立即返回。
int PThread_mutex_unlock(PThread_mutex_t *mutex);
函数 PThread_mutex_unlock 释放互斥锁对象。互斥锁如何释放取决于互斥锁的类型属性。如果在调用 PThread_mutex_unlock 时有线程阻塞在互斥锁对象上,这个互斥锁被称为,然后互斥锁变为可用状态,并且调度策略用于确定哪个线程将获得该互斥锁。
本文链接:http://so.lmcjl.com/news/17365/