POSIX thread
- 格式:doc
- 大小:140.50 KB
- 文档页数:21
linux pthread_create 参数Linux线程的创建是一个非常重要的话题,因为线程是一个应用程序中最基本的实体之一。
Linux中的线程是使用POSIX线程库(Pthread)实现的。
该库使得在Linux系统中使用线程非常方便。
本文将介绍Pthread库中的pthead_create()函数及其参数。
pthread_create() 函数原型:``` int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg); ```pthread_create 函数接受四个参数1.参数(thread): 指向pthread_t类型的指针,用来保存线程ID。
2.参数(attr): 指向 pthread_attr_t 类型的指针,用于设置线程的属性。
通常设置为NULL,使用默认属性。
3.参数(start_routine): 线程函数指针,该函数必须接受一个(void *)类型的参数,并返回一个(void *)类型的指针。
4.参数(arg): 传递给线程函数(start_routine)的参数。
线程创建完成后,它会执行调用 pthread_create() 函数的进程中的start_routine()函数,并将传递给pthread_create() 函数的参数(arg)传递给start_routine()函数。
以下是本函数传入的参数的详细说明。
1.参数(thread)参数thread是一个指针类型的变量,用来保存线程的ID。
在进程中创建一个线程时,线程的ID将存储在此指针中。
这个参数是必需的。
2.参数(attr)参数attr是一个指向pthread_attr_t类型结构体的指针。
pthread_attr_t是Linux系统中线程的属性类型,这个结构体包含了很多控制线程性质的变量,比如优先级,调度策略等等。
posix接口实现方法以POSIX接口实现方法为标题的文章POSIX(Portable Operating System Interface)是一种操作系统接口标准,旨在提供可移植性和互操作性。
POSIX接口定义了一组函数、命令和工具,用于应用程序与操作系统进行通信和交互。
本文将介绍一些常见的POSIX接口实现方法,并探讨它们在不同情况下的应用。
一、文件和目录操作接口1. 创建文件:使用open函数创建一个新文件,可以指定文件的权限和打开模式。
如果文件已存在,则会打开该文件;如果文件不存在,则会创建一个新文件。
2. 读取文件内容:使用read函数从文件中读取数据。
该函数要求提供文件描述符、缓冲区和读取的字节数,返回实际读取的字节数。
3. 写入文件内容:使用write函数将数据写入文件。
该函数要求提供文件描述符、缓冲区和写入的字节数,返回实际写入的字节数。
4. 关闭文件:使用close函数关闭文件,释放文件描述符。
5. 创建目录:使用mkdir函数创建一个新目录。
可以指定目录的权限和路径。
6. 删除目录:使用rmdir函数删除一个空目录。
7. 遍历目录:使用opendir函数打开一个目录,使用readdir函数读取目录中的文件和子目录。
二、进程管理接口1. 创建进程:使用fork函数创建一个新进程,该进程是调用进程的副本。
父进程与子进程共享代码段,但拥有独立的数据段和堆栈。
2. 等待进程结束:使用wait函数等待子进程结束,并获取子进程的返回状态。
3. 进程替换:使用exec函数族中的execve函数将当前进程替换为新的可执行文件。
该函数要求提供新程序的路径和参数。
4. 进程退出:使用exit函数终止当前进程,并返回一个退出状态。
5. 进程间通信:使用管道、共享内存、信号量等机制实现进程间的通信和同步。
三、线程管理接口1. 创建线程:使用pthread_create函数创建一个新线程。
该函数要求提供线程属性、线程入口函数和参数。
c语言创建线程的方法在C语言中,可以使用标准库中的`pthread`(POSIX Threads)来创建和管理线程。
以下是使用`pthread`库创建线程的基本步骤:1. 包含头文件:在程序中包含`pthread.h`头文件。
```c#include <pthread.h>```2. 定义线程函数:创建一个函数,该函数将作为新线程的入口点。
该函数的原型应为`void *function(void *arg)`,其中`arg`是传递给线程的参数,可以为NULL。
```cvoid *myThreadFunction(void *arg) {// 线程的具体执行逻辑// ...return NULL;}```3. 声明线程变量:声明一个`pthread_t`类型的变量,用于存储新线程的标识符。
```cpthread_t myThread;```4. 创建线程:使用`pthread_create`函数创建新线程。
```cint pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void *), void *arg);```- `thread`: 用于存储新线程标识符的变量的地址。
- `attr`: 线程的属性,通常使用`NULL`表示默认属性。
- `start_routine`: 新线程的入口函数。
- `arg`: 传递给线程函数的参数。
```cint result = pthread_create(&myThread, NULL, myThreadFunction, NULL);if (result != 0) {perror("Thread creation failed");// 处理线程创建失败的情况}```5. 等待线程结束(可选):使用`pthread_join`函数等待线程的结束。
Linux系统线程创建及同步互斥方法简要说明(供查考)1、.POSIX线程函数的定义在头文件pthread.h中,所有的多线程程序都必须通过使用#include<pthread.h>包含这个头文件2、用gcc编译多线程程序时,必须与pthread函数库连接。
可以使用以下两种方式编译(建议使用第一种)(1)gcc –D_REENTRANT -o 编译后的目标文件名源文件名-lpthread例如:gcc –D_REENTRANT -o pthread_create pthread_create.c -lpthread (执行该编译结果的方式为:./pthread_create)(2)gcc -pthread -o 编译后的文件名源文件名例如:gcc -pthread -o example example.c一、需要用到的函数的用法提示1、创建线程函数pthread_t a_thread; /*声明a_thread变量,用来存放创建的新线程的线程ID(线程标识符)*/int res=pthread_create(&a_thread,NULL,thread_function,NULL);/*创建一个执行函数thread_function的新线程,线程ID存放在变量a_thread */ 2、退出线程函数pthread_exit(NULL);/*那个线程在执行中调用了该方法,那个线程就退出*/创建和退出线程实例3、连接(等待)线程函数int error;int *exitcodeppthread_t tid; /*用来表示一个已经存在的线程*/error=pthread_join(tid,&exitcodep); /*执行该方法的线程将要一直等待,直到tid 表示的线程执行结束,exitcodep 存放线程tid退出时的返回值*/4、返回线程ID的函数pthread_t t/*声明表示线程的变量t */t=pthread_self( ) /*返回调用该方法的线程的线程ID*/5、判断两个线程是否相等的函数(pthread_equal)int pthread_equal(pthread_t t1, pthread_t t2);/*判断线程t1与线程t2是否线程ID相等*/二、线程同步1、使用互斥量同步线程(实现互斥)(1)互斥量的创建和初始化pthread_mutex_t a_mutex=PTHREAD_MUTEX_INITIALIZER/*声明a_mutex为互斥量,并且初始化为PTHREAD_MUTEX_INITIALIZER */ (2)锁定和解除锁定互斥量pthread_mutex_t a_mutex=PTHREAD_MUTEX_INITIALIZER/*声明互斥量a_mutex*/int rc=pthread_mutex_lock(&a_mutex) /*锁定互斥量a_mutex*/ ………………………………/*锁定后的操作*/int rd= pthread_mutex_unlock(&a_mutex) /*解除对互斥量a_mutex的锁定*/例子:利用互斥量来保护一个临界区pthread_mutex_t a_mutex=PTHREAD_MUTEX_INITIALIZER;pthread_mutex_lock(&a_mutex) /*锁定互斥量a_mutex*//*临界区资源*/pthread_mutex_unlock(&a_mutex) /*解除互斥量a_mutex的锁定*/(3)销毁互斥量Int rc=pthread_mutex_destory(&a_mutex) /*销毁互斥量a_mutex*/2、用条件变量同步线程(实现真正的同步)条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。
POSIX 多线程程序设计Blaise Barney, Lawrence Livermore National Laboratory目录表1.摘要2.Pthreads 概述1.什么是线程?2.什么是Pthreads?3.为什么使用Pthreads?4.使用线程设计程序3.Pthreads API编译多线程程序4.线程管理1.创建和终止线程2.向线程传递参数3.连接(Joining)和分离(Detaching)线程4.栈管理5.其它函数5.互斥量(Mutex Variables)1.互斥量概述2.创建和销毁互斥量3.锁定(Locking)和解锁(Unlocking)互斥量6.条件变量(Condition Variable)1.条件变量概述2.创建和销毁条件变量3.等待(Waiting)和发送信号(Signaling)7.没有覆盖的主题8.Pthread 库API参考9.参考资料在多处理器共享内存的架构中(如:对称多处理系统SMP),线程可以用于实现程序的并行性。
历史上硬件销售商实现了各种私有版本的多线程库,使得软件开发者不得不关心它的移植性。
对于UNIX系统,IEEE POSIX 1003.1标准定义了一个C语言多线程编程接口。
依附于该标准的实现被称为POSIX theads 或Pthreads。
该教程介绍了Pthreads的概念、动机和设计思想。
内容包含了Pthreads API主要的三大类函数:线程管理(Thread Managment)、互斥量(Mutex Variables)和条件变量(Condition Variables)。
向刚开始学习Pthreads的程序员提供了演示例程。
适于:刚开始学习使用线程实现并行程序设计;对于C并行程序设计有基本了解。
不熟悉并行程序设计的可以参考EC3500: Introduction To Parallel Computing。
什么是线程?•技术上,线程可以定义为:可以被操作系统调度的独立的指令流。
posix接口标准POSIX接口标准简介POSIX(可移植操作系统接口)是一组定义了操作系统接口的标准。
它的目的是为了实现操作系统的可移植性,使得开发者可以在不同的操作系统上编写可移植的软件。
POSIX定义了许多功能、命令以及系统调用,以便于开发者编写可移植的软件,并且保持对不同系统的一致性。
POSIX标准的内容POSIX接口标准包含了许多不同的组件,以下是其中几个重要的组件:1. 文件和目录操作:POSIX定义了一系列函数,使得开发者可以对文件和目录进行读、写、创建等操作。
例如,开发者可以使用open()函数打开一个文件,并使用read()和write()函数进行数据的读取和写入。
此外,POSIX还定义了一些标准的文件和目录路径,以及文件权限的控制。
2. 进程控制:POSIX提供了一套用于进程控制的函数。
开发者可以使用fork()函数创建一个新的进程,使用exec()函数来加载新程序并替换当前进程的地址空间,以及使用wait()函数等待一个子进程的结束。
这些函数使得进程的创建、管理和通信变得更加容易。
3. 线程控制:POSIX对线程控制也进行了定义。
通过使用线程,可以实现并发执行的能力,从而提高程序的性能。
POSIX定义了线程的创建、同步和销毁等操作。
开发者可以使用pthread_create()函数创建线程,使用mutex和condition variable等机制进行线程同步。
4. 信号处理:POSIX提供了一套用于处理信号的函数,使得开发者可以对软件中出现的不同事件做出响应。
开发者可以使用signal()函数来定义信号的处理程序,以及使用sigprocmask()来管理进程的信号屏蔽集。
5. 文件I/O:POSIX定义了标准的文件I/O接口和相关函数。
开发者可以使用fopen()和fclose()函数打开和关闭文件,使用fgets()和fputs()函数进行文件的读写操作,以及使用fseek()和ftell()函数进行文件指针的定位和查询。
pthread_tryjoin_np用法一、概述pthread_tryjoin_np是POSIX线程(pthread)库中的一个函数,用于尝试获取线程的退出状态,而无需等待该线程终止。
这对于某些情况下需要检查线程是否已经结束,但又不希望阻塞当前线程的执行很有用。
二、函数原型intpthread_tryjoin_np(pthread_tthread,void**ptr);三、参数说明*`thread`:要尝试获取退出的线程的标识符。
*`ptr`:一个指向要传递给线程的内存地址的指针,该地址在成功获取线程退出状态后将被返回。
如果此参数为NULL,则不会返回任何值。
四、函数返回值如果成功获取了线程的退出状态并返回目标内存地址,则函数返回0。
如果线程仍在运行,则返回一个非零值,表示操作失败。
五、注意事项*pthread_tryjoin_np与pthread_join的区别在于,前者只是尝试获取线程的退出状态,而不会等待线程终止。
因此,它不会阻塞当前线程的执行。
*如果线程已经退出,但仍然有多个线程试图获取其退出状态,则可能会发生竞态条件,这取决于系统如何处理这些尝试。
在这种情况下,应该使用其他机制来同步对线程状态的访问。
*传递给线程的内存地址必须在调用pthread_tryjoin_np之前分配,并且必须足够大以容纳返回的值。
六、示例代码下面是一个简单的示例代码,展示了如何使用pthread_tryjoin_np函数:```c#include<pthread.h>#include<stdio.h>#include<stdlib.h>intmain(){pthread_tthread;int*value;intresult;//创建并启动线程result=pthread_create(&thread,NULL,&thread_function,NULL);if(result!=0){perror("Threadcreationfailed");exit(EXIT_FAILURE);}//尝试获取线程退出状态并打印结果值value=malloc(sizeof(int));//分配内存地址result=pthread_tryjoin_np(thread,value);if(result==0){printf("Threadexitedwithvalue:%d\n",*value);}else{printf("Threadisstillrunning\n");}//等待线程结束(可选)pthread_join(thread,NULL);//不阻塞当前线程的执行free(value);//释放内存地址return0;}```上述代码中,首先创建并启动一个线程,然后尝试使用pthread_tryjoin_np 函数获取该线程的退出状态。
posix接口标准一、概述POSIX(Portable Operating System Interface)接口标准是由IEEE和ISO/IEC联合制定的一组操作系统接口规范,旨在实现不同操作系统之间的兼容性和互操作性。
其中,POSIX API(应用程序接口)是POSIX标准的核心组成部分,它定义了一组常用的系统调用,为开发人员提供了访问操作系统功能的途径。
二、posix接口标准的主要内容1. 进程管理(1)fork():创建一个新进程,复制父进程的映像。
(2)exec():加载可执行文件,替换当前进程的映像。
(3)exit():终止进程。
(4)wait():等待子进程结束。
(5)signal():设置信号处理函数。
2. 文件操作(1)open():打开文件。
(2)read()、write():读写文件。
(3)lseek():改变文件偏移量。
(4)close():关闭文件。
(5)stat()、lstat()、fstat():获取文件属性。
3. 进程间通信(1)pipe():创建管道。
(2)readline()、read():从管道读取数据。
(3)write():向管道写入数据。
(4)fork()+exec():使用管道执行子进程。
4. 信号处理(1)signal():设置信号处理函数。
(2)raise():发送信号。
(3)kill():发送信号给进程或线程。
5. 线程管理(1)pthread_create():创建线程。
(2)pthread_join():等待线程结束。
(3)pthread_exit():退出线程。
(4)pthread_setname_np():设置线程名称。
三、posix接口标准的特点与应用场景POSIX接口标准具有以下特点:1. 兼容性好:POSIX接口标准遵循统一的标准规范,不同操作系统之间的兼容性较好。
2. 易用性:POSIX接口提供了常用的系统调用,方便开发人员快速实现功能。
C语⾔多线程操作多线程是多任务处理的⼀种特殊形式,多任务处理允许让电脑同时运⾏两个或两个以上的程序。
⼀般情况下,两种类型的多任务处理:基于进程和基于线程。
基于进程的多任务处理是程序的并发执⾏。
基于线程的多任务处理是同⼀程序的⽚段的并发执⾏。
多线程程序包含可以同时运⾏的两个或多个部分。
这样的程序中的每个部分称为⼀个线程,每个线程定义了⼀个单独的执⾏路径。
本教程假设您使⽤的是 Linux 操作系统,我们要使⽤ POSIX 编写多线程 C++ 程序。
POSIX Threads 或 Pthreads 提供的 API 可在多种类 Unix POSIX 系统上可⽤,⽐如 FreeBSD、NetBSD、GNU/Linux、Mac OS X 和 Solaris。
下⾯的程序,我们可以⽤它来创建⼀个POSIX 线程:#include <pthread.h>pthread_create (thread, attr, start_routine, arg)在这⾥,pthread_create 创建⼀个新的线程,并让它可执⾏。
下⾯是关于参数的说明:参数描述thread指向线程标识符指针。
attr⼀个不透明的属性对象,可以被⽤来设置线程属性。
您可以指定线程属性对象,也可以使⽤默认值 NULL。
start_routine线程运⾏函数起始地址,⼀旦线程被创建就会执⾏。
arg运⾏函数的参数。
它必须通过把引⽤作为指针强制转换为 void 类型进⾏传递。
如果没有传递参数,则使⽤ NULL。
创建线程成功时,函数返回 0,若返回值不为 0 则说明创建线程失败。
使⽤下⾯的程序,我们可以⽤它来终⽌⼀个 POSIX 线程:#include <pthread.h>pthread_exit (status)在这⾥,pthread_exit ⽤于显式地退出⼀个线程。
通常情况下,pthread_exit() 函数是在线程完成⼯作后⽆需继续存在时被调⽤。
c语言多线程的三种实现方式1 C语言多线程实现C语言语言既可以用于创建单线程应用程序,也可以用于创建多线程应用程序。
它的多线程实现有三种方式:POSIX线程库(Pthread),Windows API,以及共享内存。
1.1 POSIX线程库(Pthread)POSIX线程库(Pthread)是Linux系统的一种线程API,它由标准POSIX提供,以实现多线程程序设计。
它提供许多函数用于创建、销毁线程,设置线程属性,等待线程完成以及通信功能等。
Pthread在多线程编程中被使用广泛,它更易于操纵,可以让多线程编程更加容易和有趣。
1.2 Windows APIWindows API 也是可用于C语言多线程编程的方式之一。
Windows API提供许多功能:创建线程,挂起线程,等待线程结束,分离线程,设置线程优先级等等。
Windows API也提供了很多函数和常量用于控制线程。
它与POSIX线程库不同,Windows API不使用POSIX线程库,而使用Windows API实现多线程程序时,同一应用程序可以具有多个线程。
1.3 共享内存共享内存是指多个进程可以访问同一个内存区域,从而使它们能够共享数据,实现常见的多线程编程任务。
在C语言中,可以使用mmap()函数将共享内存映射成文件描述符,在一定范围内允许多个进程对共享内存的随机读写访问。
这是一种实现多线程的方式,能够极大地提高程序的效率。
以上就是C语言中多线程实现的三种方式。
POSIX线程库(Pthread)可以简易实现,更能让多线程编程更加容易和有趣;Windows API也可以实现多线程编程,可以让同一应用程序有多个线程;共享内存是一种实现多线程的方法,能够极大地提高程序的效率。
c++ 多线程的实现方式在C++中,有多种方式可以实现多线程。
以下是其中几种常用的实现方式:1. 使用<thread>库:C++11标准引入了<thread>库,使得多线程编程变得更加容易。
可以通过创建std::thread对象来创建并启动新线程。
```cpp#include <iostream>#include <thread>void myThreadFunc() {// 线程执行的代码// ...}int main() {std::thread myThread(myThreadFunc); // 创建新线程myThread.join(); // 等待线程执行完成return 0;}```2. 使用OpenMP库:OpenMP是一种支持并行计算的开发库,可以用于在C++代码中实现多线程。
```cpp#include <iostream>#include <omp.h>void myThreadFunc() {// 线程执行的代码// ...}int main() {#pragma omp parallel{myThreadFunc(); // 并行执行myThreadFunc函数}return 0;}```3. 使用POSIX线程库:POSIX线程库是一种跨平台的多线程库,可以在包括Linux在内的许多操作系统上使用。
```cpp#include <iostream>#include <pthread.h>void* myThreadFunc(void* arg) {// 线程执行的代码// ...return nullptr;}int main() {pthread_t myThread;pthread_create(&myThread, nullptr, myThreadFunc, nullptr); // 创建新线程pthread_join(myThread, nullptr); // 等待线程执行完成return 0;}```以上是几种常见的C++多线程实现方式。
c 多线程实现的四种方式C 编程语言是一种非常流行的编程语言,使用广泛且应用广泛。
如今,许多程序员都在寻找更有效的方式来编写多线程程序。
在这篇文章中,我们将介绍 C 多线程实现的四种方式。
1. POSIX 线程库POSIX 线程库是用于编写可移植线程程序的标准 C 库。
它提供了一组函数和数据结构,使程序员能够创建和管理线程。
POSIX 线程库是跨平台的,可在多个操作系统上使用,包括 Linux、Unix 和 MacOS。
在 POSIX 线程库中,程序员使用 pthread.h 头文件来访问对线程库的访问函数。
其中一些关键函数包括pthread_create()、pthread_join() 和pthread_mutex_lock()。
2. Win32 APIWin32 API 是面向 Windows 操作系统的 API。
它是微软 Windows 操作系统的基础。
使用 Win32 API,程序员可以创建和管理线程。
Win32 API 使用 CreateThread() 函数创建线程,并使用 WaitForSingleObject() 函数等待线程完成。
Win32 API 的优点是它可以与其他 Windows API 一起使用。
它还支持在 Windows 平台上编写 C++ 和 C# 程序。
3. OpenMPOpenMP 是一种非常流行的多线程编程模型。
它适用于共享内存系统上的并行编程。
OpenMP 定义了一组编译器指示符,程序员可以在其代码中使用这些指示符以指示哪些部分应并行执行。
在 OpenMP 中,程序员可以使用 #pragma 指令来指示程序应该并行执行哪些代码块。
程序员可以控制 OpenMP 应该使用多少个线程。
4. Pthreads for WindowsPthreads for Windows 是 POSIX 线程库的 Windows 版本。
它使用 pthreads-w32 库提供相同的接口和功能,与 Windows 和 Visual Studio 兼容。
linux多线程的实现方式Linux是一种支持多线程的操作系统,它提供了许多不同的方式来实现多线程。
本文将介绍Linux多线程的几种实现方式。
1. 线程库Linux提供了线程库,包括POSIX线程库(Pthreads)和LinuxThreads。
Pthreads是一种由IEEE组织制定的标准线程库,它提供了一组线程API,可以在不同的操作系统上实现。
LinuxThreads 是Linux内核提供的线程实现,不同于Pthreads,它不是标准线程库,但具有更好的性能。
使用线程库可以方便地创建和管理线程,线程库提供了许多API 函数,例如pthread_create(),pthread_join(),pthread_mutex_lock()等,可以在程序中使用这些API函数来实现多线程。
2. 多进程在Linux中,多进程也是一种实现多线程的方式。
每个进程都可以有自己的线程,进程之间也可以通过IPC机制进行通信。
多进程的优点是可以更好地利用多核CPU,因为每个进程都可以在不同的CPU核心上运行。
但是,多进程的开销比多线程大,因为每个进程都需要拥有自己的地址空间和运行环境。
3. 线程池线程池是一种常见的多线程实现方式。
线程池中有多个线程可以处理任务,任务可以通过任务队列来进行分发。
当任务到达时,线程池中的线程会从任务队列中取出任务并处理。
线程池的优点是可以重复利用线程,减少创建和销毁线程的开销。
线程池还可以控制线程的数量,避免过多线程导致的性能下降。
4. 协程协程是一种轻量级线程,它不需要操作系统的支持,可以在用户空间中实现。
协程基于线程,但是不需要线程上下文切换的开销,因为协程可以在同一个线程内进行切换。
协程的优点是可以更好地利用CPU,因为不需要线程上下文切换的开销。
协程还可以更好地控制并发性,因为协程的切换是由程序员控制的。
总结Linux提供了多种实现多线程的方式,每种方式都有其优点和缺点。
在选择多线程实现方式时,需要考虑到应用程序的特点和需求,选择最适合的实现方式。
从pthread到Win32thread——Lilytask2.5基于Win32thread的实现段孟成(dmc@)Lilytask是以任务为单位的并行编程模型,Lilytask2.5β版最初是在Linux系统上基于POSIX thread实现的,为了更好的适应并行计算环境中的异构性,又在β版的基础上实现了for Windows版,在实现过程中,需要用Win32thread library替换POSIX thread library,下文将主要描述POSIX thread(下文称之pthread)与Win32thread的关系以及在Lilytask2.5 for Windows中的具体实现。
一.什么是线程。
线程(thread)是为了提高系统内程序的并发(concurrency)执行程度而提出来的概念,它是比进程更小的能够独立运行的基本单位。
在引入线程的系统中,线程是处理器调度(schedule)的基本单位,而传统的进程则只是资源分配的基本单位。
同一进程中的线程共享这个进程的全部资源与地址空间,除此之外,线程基本上不拥有其他任何系统资源,当然,每个线程也必须拥有自己的程序计数器(Program Counter),寄存器堆(register file)和栈(stack)等等。
即线程是一个轻量级实体(light-weight entity),它的结构(thread structure)相对简单,在切换速度上非常得快,同一进程中的线程切换不会引起进程的切换,对于并行计算来讲,有效的利用线程能够改善计算的效率,简化计算的复杂性,所以Lilytask正是基于线程实现的。
二.线程的标准。
目前,主要有三种不同的线程库的定义,分别是Win32,OS/2,以及POSIX,前两种定义只适合于他们各自的平台,而POSIX 定义的线程库是适用于所有的计算平台的,目前基本上所有基于UNIX的系统都实现了pthread。
本文主要讨论Win32和POSIX的线程定义。
pthread条件变量Pthread条件变量Pthread是POSIX线程的缩写,它支持多线程编程的标准API。
Pthread 提供了多种类型的线程的同步和互斥手段,其中条件变量也是Pthread 线程同步的一种重要方式。
什么是条件变量条件变量是一种Pthread线程同步机制,用于线程之间的通信。
条件变量用于等待另一个线程发出一个信号或广播,在某种条件得到满足时唤醒等待的线程。
条件变量API条件变量需要配合互斥锁一起使用,一般结构如下:pthread_mutex_t mutex;pthread_cond_t cond;其中mutex为一个互斥锁,而cond就是条件变量。
条件变量有三个主要API:1. pthread_cond_wait线程阻塞自己,等待条件变量被唤醒。
此函数会首先对mutex加锁,然后释放mutex并阻塞等待条件变量被信号唤醒。
当条件被激活后,线程会重新获得mutex,并继续执行。
2. pthread_cond_signal唤醒已经等待该条件变量的线程,至少唤醒其中一个线程并让其继续执行。
3. pthread_cond_broadcast唤醒已经等待该条件变量的所有线程,让它们继续执行。
示例程序以下是一个简单的示例程序,演示如何使用条件变量:```c#include <stdio.h>#include <stdlib.h>#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int count = 0;void* thread1(void *arg){pthread_mutex_lock(&mutex);printf("thread1: lock is acquired\n");while(count<5){printf("thread1: wait for condition signal\n");pthread_cond_wait(&cond,&mutex);printf("thread1: signal is received\n");count++;}printf("thread1: unlock is called\n");pthread_mutex_unlock(&mutex);return NULL;}void* thread2(void *arg){printf("thread2: lock is called\n");pthread_mutex_lock(&mutex);printf("thread2: broadcast is called\n");pthread_cond_broadcast(&cond);printf("thread2: unlock is called\n");pthread_mutex_unlock(&mutex);return NULL;}int main(void){pthread_t tid1, tid2;pthread_create(&tid1, NULL, &thread1, NULL);sleep(3);pthread_create(&tid2, NULL, &thread2, NULL);pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;}```上述程序使用了两个线程,线程1在等待条件变量被唤醒,而线程2则调用broadcast函数,唤醒线程1并使其继续执行。
linux postthreadmessage 参数Linux中的post_thread_message函数是一种线程间通信的方法,可以用来发送消息到目标线程的消息队列中。
本文将详细介绍post_thread_message函数的参数和使用方法。
post_thread_message函数是Linux下POSIX线程库提供的一个函数,它的原型如下:```cint post_thread_message(pthread_t thread, int msg_type, void *msg);```其中,参数解释如下:- `thread`:目标线程的线程ID,可以使用pthread_create函数创建线程时获取。
- `msg_type`:消息类型,可以是一个整数,用来区分不同的消息。
- `msg`:要发送的消息的内容,可以是任意类型的指针。
函数的返回值为0表示成功发送消息,否则返回一个错误码。
使用post_thread_message函数时,我们需要先创建目标线程并获得其线程ID。
下面是一个使用post_thread_message函数实现线程间通信的示例。
首先,我们需要在程序中定义一个全局变量来存储接收到的消息:```cvoid *received_msg;```然后,在目标线程的入口函数中,使用一个无限循环来接收消息,并根据消息类型进行相应的处理:```cvoid *thread_func(void *arg) {while(1) {int msg_type;void *msg;if(post_thread_message(pthread_self(), &msg_type, &msg) == 0) {switch(msg_type) {case MSG_TYPE_1:// 处理消息类型1break;case MSG_TYPE_2:// 处理消息类型2break;// 其他消息类型的处理}}}return NULL;}```在其他线程中,我们可以使用post_thread_message函数来向目标线程发送消息:```cint main() {// 创建目标线程,并获取线程ID保存在变量thread中pthread_t thread;pthread_create(&thread, NULL, thread_func, NULL);// 发送消息到目标线程int msg_type = MSG_TYPE_1;void *msg = "Hello, world!";post_thread_message(thread, msg_type, &msg);// 其他操作pthread_join(thread, NULL);return 0;}```在上面的示例中,我们首先创建了一个目标线程,并获取其线程ID保存在变量thread中。
POSIX 线程详解 1POSIX(可移植操作系统接口)线程是提高代码响应和性能的有力手段。
在本系列中,Daniel Robbins 向您精确地展示在编程中如何使用线程。
其中还涉及大量幕后细节,读完本系列文章,您完全可以运用POSIX 线程创建多线程程序。
线程是有趣的了解如何正确运用线程是每一个优秀程序员必备的素质。
线程类似于进程。
如同进程,线程由内核按时间分片进行管理。
在单处理器系统中,内核使用时间分片来模拟线程的并发执行,这种方式和进程的相同。
而在多处理器系统中,如同多个进程,线程实际上一样可以并发执行。
那么为什么对于大多数合作性任务,多线程比多个独立的进程更优越呢?这是因为,线程共享相同的内存空间。
不同的线程可以存取内存中的同一个变量。
所以,程序中的所有线程都可以读或写声明过的全局变量。
如果曾用 fork() 编写过重要代码,就会认识到这个工具的重要性。
为什么呢?虽然 fork() 允许创建多个进程,但它还会带来以下通信问题: 如何让多个进程相互通信,这里每个进程都有各自独立的内存空间。
对这个问题没有一个简单的答案。
虽然有许多不同种类的本地 IPC (进程间通信),但它们都遇到两个重要障碍:强加了某种形式的额外内核开销,从而降低性能。
对于大多数情形,IPC 不是对于代码的“自然”扩展。
通常极大地增加了程序的复杂性。
双重坏事: 开销和复杂性都非好事。
如果曾经为了支持 IPC 而对程序大动干戈过,那么您就会真正欣赏线程提供的简单共享内存机制。
由于所有的线程都驻留在同一内存空间,POSIX 线程无需进行开销大而复杂的长距离调用。
只要利用简单的同步机制,程序中所有的线程都可以读取和修改已有的数据结构。
而无需将数据经由文件描述符转储或挤入紧窄的共享内存空间。
仅此一个原因,就足以让您考虑应该采用单进程/多线程模式而非多进程/单线程模式。
线程是快捷的不仅如此。
线程同样还是非常快捷的。
与标准 fork() 相比,线程带来的开销很小。
内核无需单独复制进程的内存空间或文件描述符等等。
这就节省了大量的 CPU 时间,使得线程创建比新进程创建快上十到一百倍。
因为这一点,可以大量使用线程而无需太过于担心带来的 CPU 或内存不足。
使用 fork() 时导致的大量 CPU 占用也不复存在。
这表示只要在程序中有意义,通常就可以创建线程。
当然,和进程一样,线程将利用多 CPU。
如果软件是针对多处理器系统设计的,这就真的是一大特性(如果软件是开放源码,则最终可能在不少平台上运行)。
特定类型线程程序(尤其是 CPU 密集型程序)的性能将随系统中处理器的数目几乎线性地提高。
如果正在编写 CPU 非常密集型的程序,则绝对想设法在代码中使用多线程。
一旦掌握了线程编码,无需使用繁琐的 IPC 和其它复杂的通信机制,就能够以全新和创造性的方法解决编码难题。
所有这些特性配合在一起使得多线程编程更有趣、快速和灵活。
线程是可移植的如果熟悉 Linux 编程,就有可能知道 __clone() 系统调用。
__clone() 类似于 fork(),同时也有许多线程的特性。
例如,使用 __clone(),新的子进程可以有选择地共享父进程的执行环境(内存空间,文件描述符等)。
这是好的一面。
但 __clone() 也有不足之处。
正如__clone() 在线帮助指出:“__clone 调用是特定于 Linux 平台的,不适用于实现可移植的程序。
欲编写线程化应用程序(多线程控制同一内存空间),最好使用实现 POSIX 1003.1c 线程 API 的库,例如 Linux-Threads 库。
参阅pthread_create(3thr)。
”虽然 __clone() 有线程的许多特性,但它是不可移植的。
当然这并不意味着代码中不能使用它。
但在软件中考虑使用 __clone() 时应当权衡这一事实。
值得庆幸的是,正如 __clone() 在线帮助指出,有一种更好的替代方案:POSIX 线程。
如果想编写可移植的多线程代码,代码可运行于 Solaris、FreeBSD、Linux 和其它平台,POSIX 线程是一种当然之选。
第一个线程下面是一个 POSIX 线程的简单示例程序:thread1.c#include#include#includevoid *thread_function(void *arg) {int i;for ( i=0; i<20; i++) {printf("Thread says hi!n");sleep(1);}return NULL;}int main(void) {pthread_t mythread;if ( pthread_create( &mythread, NULL, thread_function, NULL) ) {printf("error creating thread.");abort();}if ( pthread_join ( mythread, NULL ) ) {printf("error joining thread.");abort();}exit(0);}要编译这个程序,只需先将程序存为 thread1.c,然后输入:$ gcc thread1.c -o thread1 -lpthread运行则输入:$ ./thread1理解 thread1.cthread1.c 是一个非常简单的线程程序。
虽然它没有实现什么有用的功能,但可以帮助理解线程的运行机制。
下面,我们一步一步地了解这个程序是干什么的。
main() 中声明了变量 mythread,类型是 pthread_t。
pthread_t 类型在 pthread.h 中定义,通常称为“线程 id”(缩写为 "tid")。
可以认为它是一种线程句柄。
mythread 声明后(记住 mythread 只是一个 "tid",或是将要创建的线程的句柄),调用 pthread_create函数创建一个真实活动的线程。
不要因为 pthread_create() 在 "if" 语句内而受其迷惑。
由于pthread_create() 执行成功时返回零而失败时则返回非零值,将 pthread_create() 函数调用放在 if() 语句中只是为了方便地检测失败的调用。
让我们查看一下 pthread_create 参数。
第一个参数 &mythread 是指向 mythread 的指针。
第二个参数当前为 NULL,可用来定义线程的某些属性。
由于缺省的线程属性是适用的,只需将该参数设为 NULL。
第三个参数是新线程启动时调用的函数名。
本例中,函数名为 thread_function()。
当 thread_function() 返回时,新线程将终止。
本例中,线程函数没有实现大的功能。
它仅将 "Thread says hi!" 输出 20 次然后退出。
注意 thread_function() 接受 void * 作为参数,同时返回值的类型也是 void *。
这表明可以用 void * 向新线程传递任意类型的数据,新线程完成时也可返回任意类型的数据。
那如何向线程传递一个任意参数?很简单。
只要利用 pthread_create() 中的第四个参数。
本例中,因为没有必要将任何数据传给微不足道的 thread_function(),所以将第四个参数设为 NULL。
您也许已推测到,在 pthread_create() 成功返回之后,程序将包含两个线程。
等一等,两个线程?我们不是只创建了一个线程吗?不错,我们只创建了一个进程。
但是主程序同样也是一个线程。
可以这样理解:如果编写的程序根本没有使用 POSIX 线程,则该程序是单线程的(这个单线程称为“主”线程)。
创建一个新线程之后程序总共就有两个线程了。
我想此时您至少有两个重要问题。
第一个问题,新线程创建之后主线程如何运行。
答案,主线程按顺序继续执行下一行程序(本例中执行 "if (pthread_join(...))")。
第二个问题,新线程结束时如何处理。
答案,新线程先停止,然后作为其清理过程的一部分,等待与另一个线程合并或“连接”。
现在,来看一下 pthread_join()。
正如 pthread_create() 将一个线程拆分为两个, pthread_join() 将两个线程合并为一个线程。
pthread_join() 的第一个参数是 tid mythread。
第二个参数是指向 void 指针的指针。
如果 void 指针不为 NULL,pthread_join 将线程的 void * 返回值放置在指定的位置上。
由于我们不必理会 thread_function() 的返回值,所以将其设为 NULL.您会注意到 thread_function() 花了 20 秒才完成。
在 thread_function() 结束很久之前,主线程就已经调用了 pthread_join()。
如果发生这种情况,主线程将中断(转向睡眠)然后等待 thread_function() 完成。
当 thread_function() 完成后, pthread_join() 将返回。
这时程序又只有一个主线程。
当程序退出时,所有新线程已经使用 pthread_join() 合并了。
这就是应该如何处理在程序中创建的每个新线程的过程。
如果没有合并一个新线程,则它仍然对系统的最大线程数限制不利。
这意味着如果未对线程做正确的清理,最终会导致 pthread_create() 调用失败。
无父,无子如果使用过 fork() 系统调用,可能熟悉父进程和子进程的概念。
当用 fork() 创建另一个新进程时,新进程是子进程,原始进程是父进程。
这创建了可能非常有用的层次关系,尤其是等待子进程终止时。
例如,waitpid() 函数让当前进程等待所有子进程终止。
waitpid() 用来在父进程中实现简单的清理过程。
而 POSIX 线程就更有意思。
您可能已经注意到我一直有意避免使用“父线程”和“子线程”的说法。
这是因为 POSIX 线程中不存在这种层次关系。
虽然主线程可以创建一个新线程,新线程可以创建另一个新线程,POSIX 线程标准将它们视为等同的层次。
所以等待子线程退出的概念在这里没有意义。
POSIX 线程标准不记录任何“家族”信息。
缺少家族信息有一个主要含意:如果要等待一个线程终止,就必须将线程的 tid 传递给 pthread_join()。
线程库无法为您断定 tid。