来源:http://blog.csdn.net/mprc_jhq/archive/2007/03/07/1522972.aspx
1. 线程管理
线程和函数调用很类似:
都与主程序(主线程)共享同样的存储空间;变量的使用范围也一样
---
线程和函数都只能调用自己函数体内定义的变量和全局变量;
差别是线程的执行和调用线程的执行是并行(异步)的,而函数和调用函数的执行是串行的,所以要注意同步和互斥;
线程在传递参数和结果返回上有自己的接口。
线程函数,如果成功都返回0,如果不成功,都会返回非零的错误码。他们不设置errno,因此调用程序不能用perror来报告错误。必须用strerror (error)处理。
1.1 用ID引用线程
POSIX线程由Pthread_t类型的ID引用。
#include <pthread.h>
pthread_t pthread_self (void) 返回自己的线程ID
int pthread_equal (pthread_t t1, pthread_t t2) 比较线程ID是否相等,相等则返回非0值,不相等,返回0
1.2 线程创建
#include <pthread.h>
int pthread_create (pthread_t *restrict thread,const pthread_attr_t *restrict attr,void *( *start_routine) (void *),void *restrict arg );
参数thread 指向新创建的线程ID。
参数attr 表示一个封装了线程的各种属性的属性对象,一般设置为NULL(默认属性)。
参数start_routine 是线程开始执行的时候调用的函数的名字。
函数start_routine 有一个由arg指定的参数,该参数是一个指向void的指针。
函数start_routine 返回一个指向void的指针,该返回值被pthread_join当作退出状态来处理。
参数arg 是传递给函数start_routine 的参数。
如果成功pthread_create 返回0,如果不成功,pthread_create返回一个非零的错误码 :
EAGAIN 系统没有创建线程所需的资源,或者创建线程会超出系统对一个进程中线程数的限制。
EINVAL attr参数是无效的
EPERM 调用程序没有适当的权限来设定调度策略或attr指定的参数
例:
#include <stdio.h>
#include <pthread.h>
void *start_routine (void *arg)
{
char *temp = (char *) arg ;
printf(“%s”, temp) ;
return NULL ;
}
int main(void)
{
int error ;
pthread tid ;
char *buf = “hello” ; //
线程是在进程的地址空间运行的,所以可以传递指针。
if ( error = pthread_create(&tid, NULL, start_routine, (void *)buf ) )
{
fprintf (stderr, “Failed to create pthread: %s/n”, strerror (error)) ;
exit(1);
}
exit(0);
}
1.3 分离和连接
在
Linux 中,缺省情况下线程是以一种可连接(joinable)状态被创建的。在可连接状态下,其他线程可以在一个线程终止时对其进行同步,然后用 pthread_join()函数恢复其终止代码。这个可连接线程的线程资源只有在它被插入之后才能释放。
在分离(detached)状态下,线程的资源在线程终止时会被立即释放。您可以通过对线程属性对象调用 pthread_attr_setdetachstate()来设置分离状态:
分离#include <pthread.h>
int pthread_detach (pthread_t thread);
pthread_detach函数成功返回0,不成功,返回一个非零的错误码如下:
EINVAL thread 对应的不是一个可接合的线程
ESRCH 没有ID为thread的线程
例1:
void *thr_fun(void *arg);
{}
int main(void)
{
int
error;
pthread_t
tid;
if(error = pthread_create(&tid, NULL, thr_fun, NULL);
{
fprintf(stderr, “Failed to create thread: %s/n”, strerror(error) );
exit(1);
}
if(error = pthread_detach(tid) )
//主线程执行分离
{
Fprintf(stderr, “Failed to detach thread: %s/n”, strerror(error);
Exit(2);
}
Exit(0);
}
例2:
void *thr_fun(void *arg)
{
int error;
if( error = pthread_detach(pthread_self()) )
//线程函数,自己分离出去
{
fprintf( stderr, “Failed to detach :%s/n”, strerror(error) );
exit(1);
}
return NULL;
}
连接#include <pthread.h>
int pthread_join (pthread_t thread ,void **value_ptr);
pthread_join函数成功返回0,不成功,返回一个非零的错误码如下:
EINVAL thread 对应的不是一个可接合的线程
ESRCH
没有ID为thread的线程
pthread_join 函数调用函数挂起,直到第一个参数指定的目标线程终止为止。
参数value_ptr 为指向返回值的指针,这个返回值由pthread_exit或者return 返回
1.4 退出和取消
1.4.1退出
#include <pthread.h>
void pthread_exit( void *value_ptr);
POSIX没有为pthread_exit 定义任何错误。
value_ptr
必须指向线程退出后仍然存在的数据,因此线程不应该为
value_ptr
使用指向自动局部数据的指针(分配在栈上)。代之以
malloc
函数分配结构或全局结构。。
例:
#include <pthread.h>
#include <string.h>
#include <stdio.h>
struct foo
{
int a;
int b;
int c;
int d;
};
void printfoo(const char *s, const struct foo *fp)
{
printf(s);
printf(" structure at 0x%x/n", (unsigned)fp);
printf(" foo.a = %d/n", fp->a);
printf(" foo.b = %d/n", (*fp).b);
printf(" foo.c = %d/n", fp->c);
printf(" foo.d = %d/n", fp->d);
}
void * thr_fn1(void *arg)
{
struct foo foo = {1,2,3,4};
printfoo("thread 1:/n", &foo);
pthread_exit( (void *)&foo ); // 返回变量的指针
}
void * thr_fn2(void *arg)
{
printf("thread 2: ID is %d/n", pthread_self());
pthread_exit( (void *)0 );
}
int main(void)
{
int err;
pthread_t tid1;
pthread_t tid2;
struct foo *fp; //定义相应变量的指针准备接收
if( err = pthread_create(&tid1, NULL, thr_fn1, NULL) )
{
fprintf( stderr, "Failed to create thread 1:%s/n", strerror(err) );
exit(1);
}
if( err = pthread_join(tid1, (void **)&fp ) ) //传递指向指针的指针给函数,获得
返回值
{
fprintf( stderr, "Failed to join thread 1:%s/n", strerror(err) );
exit(2);
}
sleep(1);
printf("parent starting second thread/n");
if( err = pthread_create(&tid2, NULL, thr_fn2, NULL) )
{
fprintf( stderr, "Failed to create thread 2:%s/n", strerror(err) );
exit(3);
}
sleep(1);
printfoo("parent:/n", fp);
}
结果:(由于struct foo foo分配在栈上,被第二个线程覆盖,出现了问题)
thread 1:
structure at 0xb7e3c430
foo.a = 1
foo.b = 2
foo.c = 3
foo.d = 4
parent starting second thread
thread 2: ID is -1209807952
parent:
structure at 0xb7e3c430
foo.a = -1208727122
foo.b = -1208557808
foo.c = -1208598540
foo.d = -1208605084
1.4.2取消
#include <pthread.h>
int pthread_cancel (pthread_t thread);
如果成功,函数返回0;不成功,返回非零的错误码,没有定义必须检测的错误;
pthread_cancel 有一个参数,这个参数是要取消的目标线程的ID。
pthread_cancel 不阻塞调用线程,发出取消请求后就返回了,结果有目标线程的类型和取消状态决定。
线程处于PTHREAD_CANCEL_ENABLE状态,它就接受取消请求(默认情况)。
线程处于PTHREAD_CANCEL_DISABLE状态,取消请求将被挂起。
pthread_setcancelstate 函数可以改变调用线程的取消状态
#include <pthread.h>
int pthread_setcancelstate( int state, int *oldstate );
如果成功,返回0;不成功,返回一个非零的错误码,没有定义必须检测的错误
state 说明要设置的新状态;oldstate 指向一个整数的指针,这个整数中装载了以前的状态。
作为一个通用的原则,改变了其取消状态或类型的函数应该在返回之前恢复他们的值。
pthread_setcanceltype函数可以改变调用线程的取消类型
#include <pthread.h>
int pthread_setcanceltype( int type, int *oldtype);
void pthread_testcancel(void);
pthread_setcanceltype函数如果成功,返回0;如果不成功就返回一个错误码,没有定义必须检测错误码
当线程取消状态是
DISABLE
时,有取消请求则会挂起该请求(称为未决请求);当线程的取消状态变为
ENALBE
时,线程将在下一个取消点上对所有的未决的取消请求进行处理:
线程处于PTHREAD_CANCEL_ASYNCHRONOUS(异步取消), 则立即取消线程;
线程处于PTHREAD_CANCEL_DEFERRED(延迟取消), 则到下一个取消点才取消线程;
pthread_testcancel函数用来设置取消点,POSIX还定义了很多一些其他取消点(详见《UNIX环境高级编程》P332 表12-7
1.5向线程传递参数并将值返回
1.5.1 线程内动态分配空间
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#define BLKSIZE 1024
#define WRITE_FLAG (O_WRONLY|O_CREAT|O_TRUNC)
#define READ_FLAG O_RDONLY
#define PERM (S_IRUSR|S_IWUSR)
int copyfd (fromfd, tofd)
{
char buf[BLKSIZE];
int readbytes;
int writebytes;
int totalbytes;
totalbytes = 0;
for ( ; ;)
{
if ( (readbytes = read(fromfd, buf, BLKSIZE)) <= 0 )
{
break;
}
if ( (writebytes = write(tofd, buf, readbytes)) == -1 )
{
break;
}
totalbytes += writebytes;
}
return totalbytes;
}
void * copyfile (void *arg)
{
int *i;
int fromfd;
int tofd;
int error;
fromfd = *((int *)arg);
tofd = *((int *)arg + 1);
i = malloc (sizeof(int));
(*)i = copyfd (fromfd, tofd);
return (void *)i;
}
int main (int argc, char *argv[])
{
int * n; //同线程函数返回值一个类型
int error;
pthread_t tid;
int fd[2];
if (argc != 3)
{
fprintf (stderr, "Usage: %s fromfile tofile/n", argv[0]);
exit(1);
}
if ( (fd[0] = open (argv[1], READ_FLAG)) == -1 )
{
perror ("Failed to open fromfile");
exit(2);
}
if ( (fd[1] = open (argv[2], WRITE_FLAG, PERM)) == -1)
{
perror ("Failed to open tofile");
exit(3);
}
if ( (error = pthread_create (&tid, NULL, copyfile, (void *)fd)) != 0 )
{
fprintf (stderr, "Failed to create thread:%s/n", strerror(error));
exit(4);
}
if ( (error = pthread_join (tid, (void **)&n)) != 0 )
{
fprintf (stderr, "Failed to join thread:%s/n", strerror(error));
exit(5);
}
printf ("copy bytes:%d/n", (*n));
exit(0);
}
程序绿色部分是线程向调用函数返回值:返回值一定是指针;返回值所指必须是malloc申请的堆上数据或者是全局变量,不可用自动的或静态的变量(栈上数据在函数完成后将被释放);
与普通函数调用返回值得关系:如果返回值是指针,所指必须是malloc申请的堆上数据或者是全局变量,不可用自动的或静态的变量(栈上数据在函数完成后将被释放);返回值还可以不是指针,则可以返回栈上数据(值拷贝性质的);
程序红色部分是主程序向线程传递参数
1.5.2 由于动态分配空间来装载单个整数效率很低;所以,另一种方法是由调用线程分配线程返回值所指空间
例:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define READ_FLAG O_RDONLY
#define WRITE_FLAG (O_WRONLY|O_CREAT|O_TRUNC)
#define PERM (S_IRUSR|S_IWUSR)
#define BLKSIZE 1024
int copyfd (int fromfd, int tofd)
{
int readbytes;
int writebytes;
int totalbytes;
char buf[BLKSIZE];
totalbytes = 0;
for (; ;)
{
if ( (readbytes = read (fromfd, buf, BLKSIZE)) <= 0 )
{
break;
}
if ( (writebytes = write (tofd, buf, readbytes)) == -1 )
{
break;
}
totalbytes += writebytes;
}
return totalbytes;
}
void * copyfilepass (void *arg)
{
int *argint;
argint = (int *)arg;
argint[2] = copyfd (argint[0], argint[1]);
close (argint[0]); //一定要关闭打开的文件描述符
close (argint[1]);
return (void *)(argint+2); //通过pthread_exit返回指针,也可以通过targs[2]直接访问
(但是不推荐)。
}
本站遵循Creative Commons Attribution 3.0 License,所有文章欢迎任何形式的转载,但请注明作者及出处,尊重他人劳动成果!
文章转载自: 罗索工作室 [ http://www.rosoo.net]
本文标题:线程模型
本文作者:mprc_jhq/ 本文来源:CSDN博客
本文地址: http://www.rosoo.net/a/201104/11190.html
文章转载自: 罗索工作室 [ http://www.rosoo.net]
本文标题:线程模型
本文作者:mprc_jhq/ 本文来源:CSDN博客
本文地址: http://www.rosoo.net/a/201104/11190.html