LINUX.ORG.RU

pthread


0

0

Как можно на некоторое время приостановить работу потока,а потом продолжить его исполнение.Спасибо

anonymous

уточни вопрос: условия остановки (из самого треда его останавливать, из другого), условия продолжения (то же самое). Снаружи управляют обычно через мутехи, посмотри pthread_cond_timedwait.

bugmaker ★★★★☆
()

Понял.Была проблема: надо чтоб результата работы потока определенное время (зависит от внешних действий) не было видно.Подумал о двух вариантах - остановить сам поток (почему и задал вопрос) или действовать через глобальную переменную,к-рая существует ТОЛЬКО ДЛЯ ЭТОГО ТРИДА и ДЛЯ ПРОЦЕССА,ОКОНЧАНИЯ КОТОРОГО СЕЙ ПОТОК ДОЛЖЕН ЖДАТЬ.Так вот,реализовал второй алгоритм.Хотя кто-то там говорит,что совместное использование глобал переменных совместно с потоками - херня,в данном случае я не соглашусь - все чинно и красиво.Может,я чего-то не учел?

anonymous
()
Ответ на: комментарий от anonymous

Не очень переносимый способ, но зачастую вполне рабочий - SIGSTOP+SIGCONT.

Murr ★★
()

Если надо ждать окончания процесса, то используй waitpid. А вообще ожидание чего-либо в потоках красиво делается через pthread_cond_wait, как правильно заметил bugmaker. Надеюсь свои глобальные переменные ты хоть mutex'ами огородил от одновременного доступа?

anonymous
()

Нет,а зачем? У меня поток один. Кстати,мужики,чтоб я тут вам голову не набивал - где об этом почитать? Только чтоб толковая инфа.Благодарю.

anonymous
()

nu i zachem tebe eti sranie pthread esli u tebya thread tol'ko odin? k tomuzhe utchti chto pthread eto polnost'yu user space realizaciya threads to est' u tebya v samom processe shedulyat'sya niti[RR cherez setitimer()] i razrulivautsya dostup k dannym poetomu kogda dohnit process dohnut vse niti, poetomu bespolezno v odnoy is niti zhdat' zaversheniya samogo processa :)

lg ★★
()
Ответ на: комментарий от lg

С чего это ты взял, что "pthread eto polnost'yu user space"? AFAIK, LinuxThreads целиком построен на kernel threads ...

Murr ★★
()

LinuxThreads i pthreads sovershenno raznye veschi

linuxthreads ispol'zuyut rfork() ili clone() chtoby plodit' niti i shedulit ih uzhe kernel, to est' kazhdaya nit' eto noviy process sozdannyi rforkom ili clone po etomu kogda dohnit odna nit' s drugimi nichego ne proishodit no i vozrastayut nakladnye rashody kernela svyazannie s ih shedulen'em

pthread eto kak ya i pisal - polnost'yu user space realizaciya, kotoraya sama derzhit contexty nitey i shedulit ih

lg ★★
()
Ответ на: комментарий от lg

Вы путаетесь в терминах.

Нет никакого "pthread". Есть спецификация POSIX threads. Есть ее реализации (например, LinuxThreads). Реализация POSIX threads может быть какой угодно - например, в Linux (LinuxThreads) она построена на kernel threads (вернее, это называется process-based threads).

Murr ★★
()
Ответ на: комментарий от lg

[root@murr root]# cat test.c

#include <pthread.h>

void myroutine (void * unused) {
return;
}

main () {
pthread_t thread;

pthread_create (&thread, NULL, myroutine, NULL);
}
[root@murr root]# gcc -o test test.c -lpthread
test.c: In function `main':
test.c:9: warning: passing arg 3 of `pthread_create' from incompatible pointer type
test.c:10:2: warning: no newline at end of file
[root@murr root]#
[root@murr root]# strace ./test

...
clone(child_stack=0x804b538, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND) = 9967
...

Murr ★★
()

Вообще, для Linux нет никакого смысла в библиотеках user-space threads, поскольку для тяжелых SMP приложений на user-space threads очень плохо масштабируется ввод-вывод (файловые ввод/вывод всегд блокирующий, как впрочем не только в Linux).

Murr ★★
()

да ничо я не путаю просто небольшой перекос с понятиями произошол типа
спецификация пон названием pthreads и реализация пон названием pthreads

[0][lg:pb][~/tmp]$ cat pt.c
#include <pthread.h>

void myroutine (void * unused) {
return;
}

main () {
pthread_t thread;

pthread_create (&thread, NULL, myroutine, NULL);
} 
[0][lg:pb][~/tmp]$ gcc -o pt pt.c -pthread
pt.c: In function `main':
pt.c:10: warning: passing arg 3 of `pthread_create' from incompatible pointer type
[0][lg:pb][~/tmp]$ ktrace ./pt
[0][lg:pb][~/tmp]$ kdump | grep setitimer
 25841 pt       CALL  setitimer(0x2,0xbfbff558,0)
 25841 pt       RET   setitimer 0
 25841 pt       CALL  setitimer(0x2,0xbfbff554,0)
 25841 pt       RET   setitimer 0
[0][lg:pb][~/tmp]$ kdump | grep rfork    
[1][lg:pb][~/tmp]$ gcc -o pt pt.c -L/usr/local/lib -llthread
pt.c: In function `main':
pt.c:10: warning: passing arg 3 of `pthread_create' from incompatible pointer type
[1][lg:pb][~/tmp]$ ktrace ./pt
[0][lg:pb][~/tmp]$ kdump | grep setitimer                   
[1][lg:pb][~/tmp]$ kdump | grep rfork                       
 25852 pt       CALL  rfork(0x16030)
 25852 pt       RET   rfork 25853/0x64fd
[0][lg:pb][~/tmp]$ 

lg ★★
()
Ответ на: комментарий от lg

Угу. В FreeBSD нити user-space, из-за отсутствия поддержки в ядре. в последние годы там вроде наблюдается прогресс - портировали Linux kernel threads и вроде некие KSE появились (типа некая поддержка в ядре для user-space scheduling, mixed-threads).

Murr ★★
()
Ответ на: комментарий от lg

А с чего ты взял, что у чувака BSD? ;) Я то просто уточнил, что POSIX threads могут быть по-разному реализованы ... (см. выше)

Murr ★★
()

готов хорошо поспорить с тезисом "тяжелых SMP приложений на user-space threads очень плохо масштабируется ввод-вывод"

как раз наоборот - если кернел только лищь раздает виртуальные процы а шедулинг происходит на user space то ето дает больший выигришь в сравнении с использованием принципа "Kaждой нити по процессу" как в linuxthreads

lg ★★
()

> В FreeBSD нити user-space, из-за отсутствия поддержки в ядре.

rfork() во FreeBSD очень давно :) - если ты про эту поддержку .. если нет то про какую?

lg ★★
()
Ответ на: комментарий от lg

Все же таки если нет поддержки со стороны ядра, то user нити плохо подходят, т.к. любой файловый ввод-вывод, который инициирует нить в контексте процесса ее полностью блокирует (в Linux любой ввод-вывод на файловой системе всегда блокирующий, во всяком случае generic функции вроде generic_file_read никогда не проверяют флажок O_NONBLOCK; в WinNT, кстати, с ее kernel нитями тоже самое - Fast I/O всегда блокируется; в FreeBSD, насколько я слышал, файловый ввод-вывод тоже всегда блокирующий).

Murr ★★
()

> Все же таки если нет поддержки со стороны ядра, то user нити плохо подходят,
> т.к. любой файловый ввод-вывод, который инициирует нить в контексте процесса ее
> полностью блокирует (в Linux любой ввод-вывод на файловой системе всегда
> блокирующий, во всяком случае generic функции вроде generic_file_read никогда
> не проверяют флажок O_NONBLOCK; в WinNT, кстати, с ее kernel нитями тоже самое
> - Fast I/O всегда блокируется; в FreeBSD, насколько я слышал, файловый
> ввод-вывод тоже всегда блокирующий).

ты всегда можешь избежать блокирование используя nonblocking режим(read вернет EAGAIN и ты уже будешь решать что дальше делать), именно так и делается в libc_r(thread awared libc)

ну как может любой ввод-вывод блокироватся? если дескриптор готов, винт не полетел, какой нибудь ресурс не занят то где может возникнуть блокировка?

> rfork() вместе с LinuxThreads и есть порт линуксовых ядреных нитей на FreeBSD

rfork() во FreeBSD уже давно, и народ просто взял LinuxThreads и портанул под использование rfork() вместо clone() - единственно чего не хватает rfork() это поддержки флага CLONE_PID что бы удавлетворить требование POSIX threads что все нити данного процесса должны иметь одинаковый pid

lg ★★
()
Ответ на: комментарий от lg

About nonblocking and EAGAIN: you see, i was just telling you that nonblocking/overlapping I/O as usual isn't nonblocking/overlapped for File I/O at all (is IS still nonblocking/overlapped for IPC I/O). You just have to look for "Fast I/O" or "Fast Devices" in Google. It is that for sure in Windows NT and Linux, still i've heard it is one of the problems for FreeBSD user-level threads.

About "how is it able to block?" - simply, every system call IS blocking, so some support from lower level driver is required for I/O to be really nonblocked. There is no such support in Linux kernel at all, there is no such support for Fast I/O in NT kernel (still, there is such support for "slow" IRP I/O).

About rfork: though the routine comes from Plan9/BSD, its current semantics is very similiar to Linux.

P.S. Sorry for English...

Murr ★★
()

please describe what you mean saying "block", "blocking"

when i say block, blocking i mean when you entering some routine(in user or kernel space) and routine can't be accomplished at a moment because some resource temporary can't meet your requirements - you will be marked as proccess that waits for something and won't be be scheduled again until resource will be ready.

> About "how is it able to block?" - simply, every system call IS blocking

is mine new system call blocks?:

int
my_syscall(int param)
{
return (param ? 0 : 1);
}

lg ★★
()
Ответ на: комментарий от lg

Видимо, слово "blocking" мы понимаем одинаково. Т.е. blocking - это ожидание на вводе-выводе, nonblocking - неожидание на вводе-выводе (данные поступают только если они находятся во внутренних буферах ОС).

Я имел в виду, что файловый ввод-вывод во многих ОС всегда (независимо от O_NONBLOCK) является блокирующим, т.е. невозможно на нем получить EAGAIN.

Вот я наваял небольшой примерчик (почти корректный за исключением предположения о том, что после lseek ОС не делает preread в кэш):
[root@murr root]# cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
main () {
      int pg_size = getpagesize ();
      int sys_pg = get_phys_pages ();
          unsigned char buf[pg_size];
      int   rawfd, i;

      rawfd = open (tmpnam(NULL), O_RDWR|O_CREAT);
          if (rawfd == -1) {
          fprintf (stderr, "failed to create temporary file!\n");
                  return -1;
          }

          // ftruncate (rawfd, pg_size*sys_pg); // AP: It never locks the needed disk space amount

          for (i=0; i<4*sys_pg; i++) {
           buf[i%pg_size] = i%pg_size; // AP: it's only to dirty the page
                                                                                // for page cache not to optimize
                                                                                // many-to-one, though it's almost impossible
                   if (write (rawfd, buf, pg_size) != pg_size) {
                                fprintf (stderr, "failed to write file!\n");
                                close (rawfd);
                                return -1;
                   }
          }
      if (fcntl (rawfd, F_SETFL, FNONBLOCK) == -1) {
                        fprintf (stderr, "failed to set nonblocking mode!\n");
                        close (rawfd);
                        return -1;
          }

      lseek (rawfd, SEEK_SET, pg_size*sys_pg*2); // AP: i hardly assume here that OS does not start readahead ...

          if (read (rawfd, buf, pg_size) == -1) {
             if (errno == EAGAIN)
                        printf ("test is successful! Looks like file I/O is really nonblocking in your system!\n");
         else printf ("failure reading file!\n");
      }
      else printf ("test is unsuccessful! Looks like file I/O is blocking!\n");
          close (rawfd);

      return 0;
}
[root@murr root]#
[root@murr root]# gcc -o test test.c
/root/tmp/ccLrTtYN.o: In function `main':
/root/tmp/ccLrTtYN.o(.text+0x3e): the use of `tmpnam' is dangerous, better use `mkstemp'
[root@murr root]# ./test
test is unsuccessful! Looks like file I/O is blocking!
[root@murr root]#

То есть я создаю большой файл и пытаюсь читать мимо кэша...

Murr ★★
()

Хотя даже readahead неважен. Важно только чтобы не было блокирующего readahead. Неблокирующий readahead не успеет заполнить кэш, т.к. времена вызова lseek и read несопоставимо меньше времени чтения в HDD.

Murr ★★
()

read() вернет -1 и errno будет EAGAIN если у тебя:
1) дескриптор ноходиться в nonblocking режиме
2) данные которые ты хочеш считать отсутствуют

если данные есть то blocking или nonblocking режим не играет роли

первый пункт выполнен, второй пункт может быть не выполнен например тогда когда
 у тебя:
 * заняты все DMA каналы
 * кончилось место в кешех
 * etc

ты путаешь наверное с тем как ето криво реализовано в некоторых ОС - типа когда
чувак запрашивает IO его навсякий случай помечают как blocking proccess
регистрат event в шедулере(например чтение какого то блока) и усыпляют этот
процесс до момента когда этот event будет выполнен, но тем некенее номинально
это не blocking IO это просто способ реализации, а вот когда этот event будет
обрабатываться и возникнет перехлест(кеш кончился к примеру) то процес
пробудят и будут смотрется флаги, если nonblocking и неуспело дочитатся то
вернется EAGAIN, если в blocking то опять же будет зарегистрен event шедулеру
что типа ждем пока кеша немного высвободится и усыпляется процес

к проге замечания такие, сделай так:

if (lseek (rawfd, SEEK_SET, pg_size*sys_pg*2) == -1) {
   fprintf(stderr, "can't lseek: %s\n", strerror(errno));
   return -2;
}

и добавь в конце вывод errno

lg ★★
()

BTW:
> Я имел в виду, что файловый ввод-вывод во многих ОС всегда (независимо от
> O_NONBLOCK) является блокирующим, т.е. невозможно на нем получить EAGAIN

невозможность получения EAGAIN не означает что ввод-вывод блокирующий, но поверь
что когда у тебя начинает сыпаться винт то его непременно получиш

lg ★★
()
Ответ на: комментарий от lg

Спасибо за поправку относительно lseek - там я действительно перепутал порядок параметров, что ессно не изменило результата.

По поводу O_NONBLOCK у меня всегда было такое представление:

если хоть сколько то данных доступно при чтении (доступны в том смысле, что для их копирования в user-space не требуется ввода-вывода, связанного с получением этих данных) - возвращается сколько есть, если данные недоступны, то при O_NONBLOCK возвращается 0/EAGAIN, при !O_NONBLOCK инициируется операция ввода-вывода и мы на ней засыпаем.

Не могли бы Вы поточнее сформулировать свое определение O_NONBLOCK, в идеале со ссылками на источники. Мне кажется такое поведение O_NONBLOCK в Linux вполне естественным, другое дело, что для файлового ввода-вывода O_NONBLOCK просто не реализован (в реальности даже aio будет блокироваться, AFAIK).

Murr ★★
()

инициирование операции ввода-вывода(в кеше нет ничего) так же не означает что будет блокировка, просто для простаты обычно предполагают что будет блокировка и усыпляют процесс но если не возникло блокировки то этот процесс на следуюшем же проходе шедулера может спокойно быть зашедуленым

> если хоть сколько то данных доступно при чтении (доступны в том смысле, что для
> их копирования в user-space не требуется ввода-вывода, связанного с получением
> этих данных) - возвращается сколько есть, если данные недоступны, то при
> O_NONBLOCK возвращается 0/EAGAIN, при !O_NONBLOCK инициируется операция
> ввода-вывода и мы на ней засыпаем.

не совсем так:
для blocking режима:
читается ровно столько сколько сказано(если не встретился eof) в не зависимости от того нужна или нет работа с диском. В случае возникновения работы с диском если данные(хоть какое-то количество) не могут быть считаны в такт шедулера то процесс засыпает

для nonblocking режима:
то же самое только если данные не могут быть в какой то момент считаны за такт то вернется столько сколько считано или EAGAIN если ввообще ниче нет в кеше и считать нельзя по какой то причине

впринципе этот один такт или несколько тактов и можно назвать блокировкой

lg ★★
()

кстати ничего удивительного в результатах проги нет - read() отработал то штатно без блокинга - вернул значение равное pg_size

lg ★★
()
Ответ на: комментарий от lg

Какие ОС так себя ведут? (Linux всегда спит на вводе-выводе submit_bh+wait_on_buffer).

И вообще не совсем понятно как можно оценить время необходимое для прочтения данных. Априорно никак. Апостериорно (ждем конца кванта?) вроде не имеет особого смысла, потому что зазря тратится процессорное время (и чего мы этим добиваемся? экономии на контекстных переключениях? так почти всегда можно на другую нить переключится).

Murr ★★
()

шедулер у тебя не только процессы шедулит - но и всевозможные таски типа прочитать пару блоков какого-то девайса - для выполнения этого таска необходим по крайней мере один такт шедулера и не обязательно должно произойти переключение контекста - например когда у тебя квант отведенный данному процессу длиннее чем выполненние этого таска(как обычно и происходит)

я линуксовую и бсдешную специфику не знаю - это я описывал поведение которое дает выигрыш перед всеми остальными известными тактиками и достаточно легко реализуемо - да и вообще что такое blocking и nonblocking в теории

скорее всего ты прав насчет реальной ситуации :)

lg ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.