Windows pthread emulation library

pthread.h в Visual Studio

Установка библиотеки pthread.h в среде Visual Studio

Н а примере Visual Studio 2012 Express Edition, Windows 7. Воспользуемся ресурсом ftp://sourceware.org/pub/pthreads-win32/dll-latest

  • 1. Скачайте все заголовочные *.h файлы из папки include и поместите их в папку include среды Visual Studio.
    Папка располагается примерно по такому адресу C:\Program Files\Microsoft Visual Studio 12.0\VC\include
  • 2. На ftp сервере перейдите в папку bin, далее в папку с подходящей архитектурой. Скопируйте в папку bin студии файл pthreadVSE2.dll.
    У меня эта папка располагается по адресу C:\Program Files\Microsoft Visual Studio 12.0\VC\bin
  • 3. Перейдите в папку lib, далее в папку с вашей архитектурой. Скопируйте файл pthreadVSE2.lib в папку lib студии.
    У меня она располагается по адресу C:\Program Files\Microsoft Visual Studio 12.0\VC\lib

Теперь появится возможность добавлять библиотеку pthread.h: Visual Studio увидит её, будет подсвечивать синтаксис и выводить подсказки.

  • 4. Создайте пустой проект. Откройте окно «Свойства проекта». Для этого либо кликните правой кнопкой мыши по имени проекта в Обозревателе решений | Свойства , либо откройте Проект | Свойства .
    Во вкладке Свойства конфигурации | Компоновщик | Ввод добавьте справа в дополнительные зависимости имя библиотеки pthreadVSE2.lib.

Добавление дополнительных зависимостей в проект с использованием библиотеки pthread.h

Каждый новый проект потребует этого шага. Для проверки напишем простое приложение

Вместо pthreadVSE2 можно качать и устанавливать файлы pthreadVC2. Но тогда и в дополнительных зависимостях придётся писать pthreadVC2.lib.

Windows pthread emulation library

The POSIX 1003.1-2001 standard defines an application programming interface (API) for writing multithreaded applications. This interface is known more commonly as pthreads . A good number of modern operating systems include a threading library of some kind: Solaris (UI) threads, Win32 threads, DCE threads, DECthreads, or any of the draft revisions of the pthreads standard. The trend is that most of these systems are slowly adopting the pthreads standard API, with application developers following suit to reduce porting woes.

Win32 does not, and is unlikely to ever, support pthreads natively. This project seeks to provide a freely available and high-quality solution to this problem.

Various individuals have been working on independent implementations of this well-documented and standardised threading API, but most of them never see the light of day. The tendency is for people to only implement what they personally need, and that usually does not help others. This project attempts to consolidate these implementations into one implementation of pthreads for Win32.

License

This implementation is free software, distributed under the GNU Lesser General Public License (LGPL).

Level of standards conformance

Pthreads-win32 currently implements a large subset of the POSIX standard threads related API. See our conformance page for a complete list of options and functions implemented as well as those that aren’t.

HTML formatted manual pages are now available inside the package and on this site. Peruse them for additional Pthreads-win32 information.

Project maintainer

The project is being maintained by Ross Johnson, who has been involved from the start in 1998. The role primarily involves integrating contributed code and problem fixes, writing some original sections and test cases, and of course, testing, packaging and distributing the product.

Acknowledgements

We would like to thank Ben Elliston for initiating the project, and John Bossom for providing us with his win32 pthreads implementation, which provided the near complete basis for this project.

Thanks to Xavier Leroy for granting permission to use and modify his LinuxThreads manual pages, and to the Open Group for their manual pages.

Thanks also to all past and present contributors to the project.

Please also see the Acknowledgements section of the latest ANNOUNCEMENT page.

How does it work?

The Win32 pthreads is normally implemented as a dynamic link library (DLL). This has some notable advantages from the Win32 point of view, but it also more closely models existing pthread libraries on UNIX which are usually shared objects (e.g. libpthread.so). Please note though, that the library can also be built for static linking if necessary.

Success stories

The library is being used in many projects either migrating from Unix platforms or developing cross-platform applications. These include commercial, research and other applications, many of which can be found via a Google search (e.g. try the keywords ‘pthreads-win32’ and ‘requirements’).

Where can I get it?


Download

[You can also get it from one of several mirror sites.]

The source tree and precompiled .DLL, .LIB and necessary header files are included in the zip file named «pthread-w32-v-v-v-release.zip» at:
ftp://sourceware.org/pub/pthreads-win32
(v-v-v is the version number, e.g. 1-4-0, and “release” is a descriptive term that may vary, e.g. beta1, rc1. Etc). Versions older than 2.9.1 are in self-extracting .exe files.

Just the DLLs, LIBs, header files, and admin documentation is available at:
ftp://sourceware.org/pub/pthreads-win32/dll-latest

The source tree is available as a gzipped tar file from:
ftp://sourceware.org/pub/pthreads-win32

The source files are also available in unpacked form at:
ftp://sourceware.org/pub/pthreads-win32/sources

Direct access to the CVS code repository

You can get anonymous read-only access to the source code using CVS (Concurrent Versioning System), from sourceware.org. If you would like to use CVS under Win32, you can get it from www.wincvs.org

To check out the most recent development version of the source code, type (or whatever the equivalent is in wincvs):

cvs -d :pserver:anonymous@sourceware.org:/cvs/pthreads-win32 checkout pthreads

Via the CVS Web page

There is also a web interface to CVS, which might suit you better if you’re more interested in just reading the code.

Читайте также:  История wifi подключений windows 10

Just want the DLL without the source code?

The latest DLL, development library, include files (pthread.h, semaphore.h, sched.h) , and ChangeLog are available from ftp://sourceware.org/pub/pthreads-win32/dll-latest

Mailing lists

A discussion list exists for this project.

To Subscribe

No subject or message is required, but will be ignored if present (some mailers may insist on one or both before sending the message).

Want to unsubscribe?

If you still get mail from the list after this then perhaps you’ve changed your address, in which case the list server won’t recognise you. If you are still getting mail forwarded to you from your old address then you can unsubscribe your old address by sending mail to

where oldname=oldhost.olddomain must be your previous address (with the ‘@’ replaced by ‘=’). A message will be sent to your old address so that you can confirm your removal. Otherwise you’ll have to notify Ross so that he can remove your previous address by hand.

Other possibilities

There are also ways to get archived mailing list messages, or messages in digest form etc.

Keeping up with code changes

Another mailing list carries CVS notification messages which are generated when modifications are checked into CVS. You can subscribe by sending mail to sourceware-cvs-pthreads-win32-request@sourceware.org. (What a mouthful!)

Project resources


Other pages

Manual pages online – edited for Pthreads-win32

How do you compile static pthread-win32 lib for x64?

It looks like some work has been done to make pthread-win32 work with x64, but there are no build instructions. I have tried simly building with the Visual Studio x64 Cross Tools Command Prompt, but when I try to link to the lib from an x64 application, it can’t see any of the function exports. It seems like it is still compiling the lib as x86 or something.

I’ve even tried adding /MACHINE to the makefile in the appropriate places, but it doesn’t help. Has anyone gotten this to work?

7 Answers 7

For me, I just use a 64-bit windows compiler (mingw-w64 cross compiler in this particular case) then make (with2.9.1) like:

Then how I install it for use (some of this may not be needed, of course),

then to use it, you have to define this (example ffmpeg configure line to use it):

Anyhow that’s one way.

Another way is to do the same then modify the *.h files and remove all references to dllexport from the headers (or manually define DPTW32_STATIC_LIB in the headers).

(ref: zeranoe build scripts)

You can use the vcpkg here. Which is the Windows package manager for C++. It supports pthread building and also other open source libraries.

I wanted to use a static pthread library. When i downloaded the pthread i got the dll(pthread.dll) and import lib(pthread.lib) i.e I can not use only pthread.lib I had to use the pthread.dll file.

So using vcpkg I have built the static lib. Which I can use without any dll dependencies

Using «vcpkg» you can build both Static and Dynamic Libraries

You can use below steps

Below i have added the steps for all DLL (x86|x64) and LIB (x86|x64) cases. You can build it as per your need.

Clone the vcpkg from git directory vcpkg git repo

From the directory where you have cloned vcpkg run below command- Which will install the vcpkg

Check for the library availability by running below commands

Which will show you below result

As you can see it supports pthread for windows

1 .Building Dynamic Library with import lib (DLL)

Building x86 DLL

Which will build the dll and import library in .\vcpkg\installed\x86-windows from here copy the lib and include and you can use them

Building x64 DLL

Which will build the dll and import library in .\vcpkg\installed\x64-windows from here copy the lib and include folders.

2. Building Static Library (LIB)

Building x86 LIB

Which will build the dll and import library in .\vcpkg\installed\x86-windows-static from here copy the lib and include and you can use them

Building x64 LIB

Which will build the dll and import library in .\vcpkg\installed\x64-windows-static from here copy the lib and include folders.

NOTE : Try to use with admin privileges

Can I get Unix’s pthread.h to compile in Windows?

If I try to compile a program with

in it, I get the error:

Is it possible to get this to compile in a Windows environment?

I am using Vista with the latest MinGW.

I do not want to use the Microsoft Windows Services for UNIX Version 3.5 as I will have to move this to a Unix environment.

5 Answers 5

pthread.h is a header for the Unix/Linux (POSIX) API for threads. A POSIX layer such as Cygwin would probably compile an app with #include

The native Windows threading API is exposed via #include and it works slightly differently to Linux’s threading.

Still, there’s a replacement «glue» library maintained at http://sourceware.org/pthreads-win32/ ; note that it has some slight incompatibilities with MinGW/VS (e.g. see here).

As @Ninefingers mentioned, pthreads are unix-only. Posix only, really.

That said, Microsoft does have a library that duplicates pthreads:

pthread.h isn’t on Windows. But Windows has extensive threading functionality, beginning with CreateThread.

My advice is don’t get caught looking at WinAPI through the lens of another system’s API. These systems are different. It’s like insisting on riding the Win32 bike with your comfortable Linux bike seat. Well, the seat might not fit right and in some cases it’ll just fall off.

Threads pretty much work the same on different systems, you have ThreadPools and mutexes. Having worked with both pthreads and Windows threads, I can say the Windows threading offers quite a bit more functionality than pthread does.

Learning another API is pretty easy, just think in terms of the concepts (mutex, etc), then look up how to create one of those on MSDN.

Just pick up the TDM-GCC 64x package. (It constains both the 32 and 64 bit versions of the MinGW toolchain and comes within a neat installer.) More importantly, it contains something called the «winpthread» library.

It comprises of the pthread.h header, libwinpthread.a , libwinpthread.dll.a static libraries for both 32-bit and 64-bit and the required .dlls libwinpthread-1.dll and libwinpthread_64-1.dll (this, as of 01-06-2016).

Читайте также:  Административные шаблоны для windows server 2012 r2

You’ll need to link to the libwinpthread.a library during build. Other than that, your code can be the same as for native Pthread code on Linux. I’ve so far successfully used it to compile a few basic Pthread programs in 64-bit on windows.

Alternatively, you can use the following library which wraps the windows threading API into the pthreads API: pthreads-win32.

The above two seem to be the most well known ways for this.

Pthreads: Потоки в русле POSIX

Современные операционные системы и микропроцессоры уже давно поддерживает многозадачность и вместе с тем, каждая из этих задач может выполняться в несколько потоков. Это дает ощутимый прирост производительности вычислений и позволяет лучше масштабировать пользовательские приложения и сервера, но за это приходится платить цену — усложняется разработка программы и ее отладка.

В этой статье мы познакомимся с POSIX Threads для того, чтобы затем узнать как это все работает в Linux. Не заходя в дебри синхронизации и сигналов, рассмотрим основные элементы Pthreads. Итак, под капотом потоки.

Общие сведения

Множественные нити исполнения в одном процессе называют потоками и это базовая единица загрузки ЦПУ, состоящая из идентификатора потока, счетчика, регистров и стека. Потоки внутри одного процесса делят секции кода, данных, а также различные ресурсы: описатели открытых файлов, учетные данные процесса сигналы, значения umask , nice , таймеры и прочее.

У всех исполняемых процессов есть как минимум один поток исполнения. Некоторые процессы этим и ограничиваются в тех случаях, когда дополнительные нити исполнения не дают прироста производительности, но только усложняют программу. Однако таких программ с каждым днем становится относительно меньше.

В чем польза множественных потоков исполнения? Возьмем какой-нибудь загруженный веб сервер, например habrahabr.ru. Если бы сервер создавал отдельный процесс для обслуживания каждого http запроса, мы бы ожидали вечно пока загрузится наша страница. Создания нового процесса — дорогостоящее удовольствие для ОС. Даже учитывая оптимизацию за счет копирования при записи, системные вызовы fork и exec создают новые копии страниц памяти и списка файловых описателей. В целом ядро ОС может создать новый поток на порядок быстрее, чем новый процесс.

Ядро задействует копирование при записи для страниц с данными, сегментов памяти родительского процесса содержащие стек и кучу. Вследствие того, что процессы часто выполняют вызов fork и сразу после этого exec , копирование их страниц во время выполнения вызова fork становится ненужной расточительностью — их все равно приходится отбрасывать после выполнения exec . Сперва записи таблицы страниц указывают на одни и те же страницы физической памяти родительского процесса, сами же страницы маркируются только для чтения. Копирование страницы происходит ровно в тот момент, когда требуется ее изменить.

Таблицы страниц до и после изменения общей страницы памяти во время копирования при записи.

Существует закономерность между количеством параллельных нитей исполнения процесса, алгоритмом программы и ростом производительности. Это зависимость называется Законом Амдаля.

Закон Амдаля для распараллеливания процессов.

Используя уравнение, показанное на рисунке, можно вычислить максимальное улучшение производительности системы, использующей N процессоров и фактор F, который указывает, какая часть системы не может быть распараллелена. Например 75% кода запускается параллельно, а 25% — последовательно. В таком случае на двухядерном процессоре будет достигнуто 1.6 кратное ускорение программы, на четырехядерном процессоре — 2.28571 кратное, а предельное значение ускорения при N стремящемся к бесконечности равно 4.

Отображение потоков в режим ядра

Практически все современные ОС — включая Windows, Linux, Mac OS X, и Solaris — поддерживают управление потоками в режиме ядра. Однако потоки могут быть созданы не только в режиме ядра, но и в режиме пользователя. При использовании этого уровня ядро не знает о существовании потоков — все управление потоками реализуется приложением с помощью специальных библиотек. Пользовательские потоки по разному отображаются на потоки в режиме ядра. Всего существует три модели, из которых 1:1 является наиболее часто используемой.

Отображение N:1

В данной модели несколько пользовательских потоков отображаются на один поток ядра ОС. Все управление потоками осуществляет особая пользовательская библиотека, и в этом преимущество такого подхода. Недостаток же в том, что если один единственный поток выполняет блокирующий вызов, то тогда тормозится весь процесс. Предыдущие версии Solaris OS использовали такую модель, но затем вынуждены были от нее отказаться.

Отображение 1:1

Это самая проста модель, в которой каждый поток созданный в каком-нибудь процессе непосредственно управляется планировщиком ядра ОС и отображается на один единственный поток в режиме ядра. Чтобы приложение не плодило бесконтрольно потоки, перегружая ОС, вводят ограничение на максимальное количество потоков поддерживаемых в ОС. Данный способ отображения потоков поддерживают ОС Linux и Windows.

Отображение M:N

При таком подходе M пользовательских потоков мультиплексируются в такое же или меньшее N количество потоков ядра. Преодолеваются негативные эффекты двух других моделей: нити по-настоящему исполняются параллельно и нет необходимости в ОС вводить ограничения на их общее количество. Вместе с тем данную модель довольно трудно реализовать с точки зрения программирования.

Потоки POSIX

В конце 1980-х и начале 1990-х было несколько разных API, но в 1995 г. POSIX.1c стандартизовал потоки POSIX, позже это стало частью спецификаций SUSv3. В наше время многоядерные процессоры проникли даже в настольные ПК и смартфоны, так что у большинства машин есть низкоуровневая аппаратная поддержка, позволяющая им одновременно выполнять несколько потоков. В былые времена одновременное исполнение потоков на одноядерных ЦПУ было лишь впечатляюще изобретательной, но очень эффективной иллюзией.

Pthreads определяет набор типов и функций на Си.

  • pthread_t — идентификатор потока;
  • pthread_mutex_t — мютекс;
  • pthread_mutexattr_t — объект атрибутов мютекса
  • pthread_cond_t — условная переменная
  • pthread_condattr_t — объект атрибута условной переменной;
  • pthread_key_t — данные, специфичные для потока;
  • pthread_once_t — контекст контроля динамической инициализации;
  • pthread_attr_t — перечень атрибутов потока.

В традиционном Unix API код последней ошибки errno является глобальной int переменной. Это однако не годится для программ с множественными нитями исполнения. В ситуации, когда вызов функции в одном из исполняемых потоков завершился ошибкой в глобальной переменной errno , может возникнуть состояние гонки из-за того, что и остальные потоки могут в данный момент проверять код ошибки и оконфузиться. В Unix и Linux эту проблему обошли тем, что errno определяется как макрос, задающий для каждой нити собственное изменяемое lvalue .

Из man errno
Переменная errno определена в стандарте ISO C как изменяемое lvalue int и не объявляемая явно; errno может быть и макросом. Переменная errno является локальным значением нити; её изменение в одной нити не влияет на её значение в другой нити.

Создание потока

В начале создается потоковая функция. Затем новый поток создается функцией pthread_create() , объявленной в заголовочном файле pthread.h. Далее, вызывающая сторона продолжает выполнять какие-то свои действия параллельно потоковой функции.

Читайте также:  Linux для компьютерного клуба

При удачном завершении pthread_create() возвращает код 0, ненулевое значение сигнализирует об ошибке.

  • Первый параметр вызова pthread_create() является адресом для хранения идентификатора создаваемого потока типа pthread_t .
  • Аргумент start является указателем на потоковую void * функцию, принимающей бестиповый указатель в качестве единственной переменной.
  • Аргумент arg — это бестиповый указатель, содержащий аргументы потока. Чаще всего arg указывает на глобальную или динамическую переменную, но если вызываемая функция не требует наличия аргументов, то в качестве arg можно указать NULL .
  • Аргумент attr также является бестиповым указателем атрибутов потока pthread_attr_t . Если этот аргумент равен NULL , то поток создается с атрибутами по умолчанию.

Рассмотрим теперь пример многопоточной программы.

Чтобы подключить библиотеку Pthread к программе, нужно передать компоновщику опцию -lpthread .

О присоединении потока pthread_join расскажу чуть позже. Строка pthread_t tid задает идентификатор потока. Атрибуты функции задает pthread_attr_init(&attr) . Так как мы не задавали их явно, будут использованы значения по умолчанию.

Завершение потока

Поток завершает выполнение задачи когда:

  • потоковая функция выполняет return и возвращает результат произведенных вычислений;
  • в результате вызова завершения исполнения потока pthread_exit() ;
  • в результате вызова отмены потока pthread_cancel() ;
  • одна из нитей совершает вызов exit()
  • основная нить в функции main() выполняет return , и в таком случае все нити процесса резко сворачиваются.

Синтаксис проще, чем при создании потока.

Если в последнем варианте старшая нить из функции main() выполнит pthread_exit() вместо просто exit() или return , то тогда остальные нити продолжат исполняться, как ни в чем не бывало.

Ожидание потока

Функция pthread_join() ожидает завершения потока обозначенного THREAD_ID . Если этот поток к тому времени был уже завершен, то функция немедленно возвращает значение. Смысл функции в том, чтобы синхронизировать потоки. Она объявлена в pthread.h следующим образом:

При удачном завершении pthread_join() возвращает код 0, ненулевое значение сигнализирует об ошибке.

Если указатель DATA отличается от NULL , то туда помещаются данные, возвращаемые потоком через функцию pthread_exit() или через инструкцию return потоковой функции. Несколько потоков не могут ждать завершения одного. Если они пытаются выполнить это, один поток завершается успешно, а все остальные — с ошибкой ESRCH. После завершения pthread_join() , пространство стека связанное с потоком, может быть использовано приложением.

В каком-то смысле pthread_joini() похожа на вызов waitpid() , ожидающую завершения исполнения процесса, но с некоторыми отличиями. Во-первых, все потоки одноранговые, среди них отсутствует иерархический порядок, в то время как процессы образуют дерево и подчинены иерархии родитель — потомок. Поэтому возможно ситуация, когда поток А, породил поток Б, тот в свою очередь заделал В, но затем после вызова функции pthread_join() А будет ожидать завершения В или же наоборот. Во-вторых, нельзя дать указание одному ожидай завершение любого потока, как это возможно с вызовом waitpid(-1, &status, options) . Также невозможно осуществить неблокирующий вызов pthread_join() .

Досрочное завершение потока

Точно так же, как при управлении процессами, иногда необходимо досрочно завершить процесс, многопоточной программе может понадобиться досрочно завершить один из потоков. Для досрочного завершения потока можно воспользоваться функцией pthread_cancel .

При удачном завершении pthread_cancel() возвращает код 0, ненулевое значение сигнализирует об ошибке.

Важно понимать, что несмотря на то, что pthread_cancel() возвращается сразу и может завершить поток досрочно, ее нельзя назвать средством принудительного завершения потоков. Дело в том, что поток не только может самостоятельно выбрать момент завершения в ответ на вызов pthread_cancel() , но и вовсе его игнорировать. Вызов функции pthread_cancel() следует рассматривать как запрос на выполнение досрочного завершения потока. Поэтому, если для вас важно, чтобы поток был удален, нужно дождаться его завершения функцией pthread_join() .

Небольшая иллюстрация создания и отмены потока.

Чтобы не создалось впечатление, что тут царит произвол и непредсказуемость результатов данного вызова, рассмотрим таблицу параметров, которые определяют поведение потока после получения вызова на досрочное завершение.

Как мы видим есть вовсе неотменяемые потоки, а поведением по умолчанию является отложенное завершение, которое происходит в момент завершения. А откуда мы узнаем, что этот самый момент наступил? Для этого существует вспомогательная функция pthread_testcancel .

Отсоединение потока

Любому потоку по умолчанию можно присоединиться вызовом pthread_join() и ожидать его завершения. Однако в некоторых случаях статус завершения потока и возврат значения нам не интересны. Все, что нам надо, это завершить поток и автоматически выгрузить ресурсы обратно в распоряжение ОС. В таких случаях мы обозначаем поток отсоединившимся и используем вызов pthread_detach() .

При удачном завершении pthread_detach() возвращает код 0, ненулевое значение сигнализирует об ошибке.

Отсоединенный поток — это приговор. Его уже не перехватить с помощью вызова pthread_join() , чтобы получить статус завершения и прочие плюшки. Также нельзя отменить его отсоединенное состояние. Вопрос на засыпку. Что будет, если завершение потока не перехватить вызовом pthread_join() и чем это отлично от сценария, при котором завершился отсоединенный поток? В первом случае мы получим зомбо-поток, а во втором — все будет норм.

Потоки versus процессы

Напоследок предлагаю рассмотреть несколько соображений на тему, следует ли проектировать приложение многопоточным или запускать его в несколько процессов с одним потоком? Сперва выгоды параллельных множественных потоков.

В начальной части статьи мы уже указывали на эти преимущество, поэтому вкратце их просто перечислим.

  • Потоки довольно просто обмениваются данными по сравнению с процессами.
  • Создавать потоки для ОС проще и быстрее, чем создавать процессы.

Теперь немного о недостатках.

  • При программировании приложения с множественными потоками необходимо обеспечить потоковую безопасность функций — т. н. thread safety. Приложения, выполняющиеся через множество процессов, не имеют таких требований.
  • Один бажный поток может повредить остальные, так как потоки делят общее адресное пространство. Процессы более изолированы друг от друга.
  • Потоки конкурируют друг с другом в адресном пространстве. Стек и локальное хранилище потока, захватывая часть виртуального адресного пространства процесса, тем самым делает его недоступным для других потоков. Для встроенных устройств такое ограничение может иметь существенное значение.

Тема потоков практически бездонна, даже основы работы с потоками может потянуть на пару лекций, но мы уже знаем достаточно, чтобы изучить структуру многопоточных приложений в Linux.

Оцените статью