уточни вопрос: условия остановки (из самого треда его останавливать, из другого), условия продолжения (то же самое). Снаружи управляют обычно через мутехи, посмотри pthread_cond_timedwait.
Понял.Была проблема: надо чтоб результата работы потока определенное время (зависит от внешних действий) не было видно.Подумал о двух вариантах - остановить сам поток (почему и задал вопрос) или действовать через глобальную переменную,к-рая существует ТОЛЬКО ДЛЯ ЭТОГО ТРИДА и ДЛЯ ПРОЦЕССА,ОКОНЧАНИЯ КОТОРОГО СЕЙ ПОТОК ДОЛЖЕН ЖДАТЬ.Так вот,реализовал второй алгоритм.Хотя кто-то там говорит,что совместное использование глобал переменных совместно с потоками - херня,в данном случае я не соглашусь - все чинно и красиво.Может,я чего-то не учел?
Если надо ждать окончания процесса, то используй waitpid. А вообще ожидание чего-либо в потоках красиво делается через pthread_cond_wait, как правильно заметил bugmaker. Надеюсь свои глобальные переменные ты хоть mutex'ами огородил от одновременного доступа?
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 :)
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
Нет никакого "pthread". Есть спецификация POSIX threads. Есть ее реализации (например, LinuxThreads). Реализация POSIX threads может быть какой угодно - например, в Linux (LinuxThreads) она построена на kernel threads (вернее, это называется process-based threads).
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
Вообще, для Linux нет никакого смысла в библиотеках user-space threads, поскольку для тяжелых SMP приложений на user-space threads очень плохо масштабируется ввод-вывод (файловые ввод/вывод всегд блокирующий, как впрочем не только в Linux).
Угу. В FreeBSD нити user-space, из-за отсутствия поддержки в ядре. в последние годы там вроде наблюдается прогресс - портировали Linux kernel threads и вроде некие KSE появились (типа некая поддержка в ядре для user-space scheduling, mixed-threads).
готов хорошо поспорить с тезисом "тяжелых SMP приложений на user-space threads очень плохо масштабируется ввод-вывод"
как раз наоборот - если кернел только лищь раздает виртуальные процы а шедулинг происходит на user space то ето дает больший выигришь в сравнении с использованием принципа "Kaждой нити по процессу" как в linuxthreads
Все же таки если нет поддержки со стороны ядра, то user нити плохо подходят, т.к. любой файловый ввод-вывод, который инициирует нить в контексте процесса ее полностью блокирует (в Linux любой ввод-вывод на файловой системе всегда блокирующий, во всяком случае generic функции вроде generic_file_read никогда не проверяют флажок O_NONBLOCK; в WinNT, кстати, с ее kernel нитями тоже самое - Fast I/O всегда блокируется; в FreeBSD, насколько я слышал, файловый ввод-вывод тоже всегда блокирующий).
> Все же таки если нет поддержки со стороны ядра, то 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
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.
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
Видимо, слово "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]#
То есть я создаю большой файл и пытаюсь читать мимо кэша...
Хотя даже readahead неважен. Важно только чтобы не было блокирующего readahead. Неблокирующий readahead не успеет заполнить кэш, т.к. времена вызова lseek и read несопоставимо меньше времени чтения в HDD.
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
BTW:
> Я имел в виду, что файловый ввод-вывод во многих ОС всегда (независимо от
> O_NONBLOCK) является блокирующим, т.е. невозможно на нем получить EAGAIN
невозможность получения EAGAIN не означает что ввод-вывод блокирующий, но поверь
что когда у тебя начинает сыпаться винт то его непременно получиш
Спасибо за поправку относительно lseek - там я действительно перепутал порядок параметров, что ессно не изменило результата.
По поводу O_NONBLOCK у меня всегда было такое представление:
если хоть сколько то данных доступно при чтении (доступны в том смысле, что для их копирования в user-space не требуется ввода-вывода, связанного с получением этих данных) - возвращается сколько есть, если данные недоступны, то при O_NONBLOCK возвращается 0/EAGAIN, при !O_NONBLOCK инициируется операция ввода-вывода и мы на ней засыпаем.
Не могли бы Вы поточнее сформулировать свое определение O_NONBLOCK, в идеале со ссылками на источники. Мне кажется такое поведение O_NONBLOCK в Linux вполне естественным, другое дело, что для файлового ввода-вывода O_NONBLOCK просто не реализован (в реальности даже aio будет блокироваться, AFAIK).
инициирование операции ввода-вывода(в кеше нет ничего) так же не означает что будет блокировка, просто для простаты обычно предполагают что будет блокировка и усыпляют процесс но если не возникло блокировки то этот процесс на следуюшем же проходе шедулера может спокойно быть зашедуленым
> если хоть сколько то данных доступно при чтении (доступны в том смысле, что для
> их копирования в user-space не требуется ввода-вывода, связанного с получением
> этих данных) - возвращается сколько есть, если данные недоступны, то при
> O_NONBLOCK возвращается 0/EAGAIN, при !O_NONBLOCK инициируется операция
> ввода-вывода и мы на ней засыпаем.
не совсем так:
для blocking режима:
читается ровно столько сколько сказано(если не встретился eof) в не зависимости от того нужна или нет работа с диском. В случае возникновения работы с диском если данные(хоть какое-то количество) не могут быть считаны в такт шедулера то процесс засыпает
для nonblocking режима:
то же самое только если данные не могут быть в какой то момент считаны за такт то вернется столько сколько считано или EAGAIN если ввообще ниче нет в кеше и считать нельзя по какой то причине
впринципе этот один такт или несколько тактов и можно назвать блокировкой
Какие ОС так себя ведут? (Linux всегда спит на вводе-выводе submit_bh+wait_on_buffer).
И вообще не совсем понятно как можно оценить время необходимое для прочтения данных. Априорно никак. Апостериорно (ждем конца кванта?) вроде не имеет особого смысла, потому что зазря тратится процессорное время (и чего мы этим добиваемся? экономии на контекстных переключениях? так почти всегда можно на другую нить переключится).
шедулер у тебя не только процессы шедулит - но и всевозможные таски типа прочитать пару блоков какого-то девайса - для выполнения этого таска необходим по крайней мере один такт шедулера и не обязательно должно произойти переключение контекста - например когда у тебя квант отведенный данному процессу длиннее чем выполненние этого таска(как обычно и происходит)
я линуксовую и бсдешную специфику не знаю - это я описывал поведение которое дает выигрыш перед всеми остальными известными тактиками и достаточно легко реализуемо - да и вообще что такое blocking и nonblocking в теории