线程取消选项
一个线程在运用的过程中一般都会用到线程取消
比如说一棵二叉树,查找某个结点,一个查找太累,用多个线程进项查找,会有一个找到,那么其他的线程就需要线程取消,然后
在收尸。正在运行的线程是无法收尸收回来的
函数
pthread_cancel();
pthread_cancel - send a cancellation request to a thread
#include <pthread.h>
int pthread_cancel(pthread_t thread);
Compile and link with -pthread.
fd = open();
if(fd<0)
{
perror();
exit(1);
}
//------>cleanup_push();--->close(fd);//挂上钩子函数,以免还没到close的时候,被取消
//但是还有可能没有挂上钩子函数,就被取消了,但是这种情况不会出现,因为不是cancel点
//下面一句是阻塞系统调用,所以cancel会在这个位置调用
fd2=open();
if(fd2<0)
{
perror();
exit(1);
}
//------>cleanup_push();--->close(fd2);
取消有2种状态,一种是允许,一种是不允许.
允许取消又分为异步取消和推迟取消(默认)
推迟取消就是推迟至cancel点(posix定义的cancel点,都是可能引发阻塞的系统调用)再响应
异步cancel,相当于一个内存操作,不牵扯到申请和释放和系统调用,一旦用到就是死,不会有什么后续的问题
pthread_setcanceltype();(设置取消方式,异步还是推迟)
pthread_setcancelstate();(设置取消状态,是否允许被取消)
pthread_setcancelstate, pthread_setcanceltype - set cancelability state
and type
#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);
Compile and link with -pthread.
pthread_testcancel();(本身就是一个取消点)就是一个取消点,什么都不做。用来设置取消点,一个程序中可能没有取消点,就会使用这个.
pthread_testcancel - request delivery of any pending cancellation
request
#include <pthread.h>
void pthread_testcancel(void);
Compile and link with -pthread.
线程分离
不关心该线程的生死存亡,一旦创建以后,就没有任何关系,就不管这个线程。如果使用join函数,就会报错
一旦分离的线程是收尸收不回来的。
pthread_detach();
pthread_detach - detach a thread
#include <pthread.h>
int pthread_detach(pthread_t thread);
Compile and link with -pthread.
线程竞争实例
筛质数:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)
static void * thr_prime(void *p);
int main()
{
int i,err;
pthread_t tid[THRNUM];
for(i=LEFT;i<=RIGHT;i++)
{
err=pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
}
for(i=LEFT;i<=RIGHT;i++)
pthread_join(tid[i-LEFT],NULL);
exit(0);
}
static void * thr_prime(void *p)
{
int i,j,mark;
i=*(int *)p;
mark=1;
for(j=2;j<i/2;j++)
{
if(i%j==0)
{
mark=0;
break;
}
}
if(mark)
printf("%d is a primer\n",i);
pthread_exit(NULL);
}
运行结果只有一个或者没有(每次运行结果几乎不一样),是不正确的,因为在这里出现了竞争,不是原子操作。
错在了地址传递,201个用了同一个地址,那么这里我们就可以换个方法,值传递,又函数需要地址类型所以将值强制转化为地址就可以,将上面的代码改两个地方就可以。 (改成如下)
err=pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);
i=(int)p;
ps axf查看进程关系
或者采用 201个i在201个空间就可以,运用malloc,实现动态分配。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)
static void * thr_prime(void *p);
struct thr_arg_st
{
int n;
};
int main()
{
int i,err;
pthread_t tid[THRNUM];
struct thr_arg_st *p;
for(i=LEFT;i<=RIGHT;i++)
{
p=malloc(sizeof(*p));
if(p==NULL)
{
perror("malloc()");
exit(1);
}
p->n=i;
err=pthread_create(tid+(i-LEFT),NULL,thr_prime,p);
}
for(i=LEFT;i<=RIGHT;i++)
pthread_join(tid[i-LEFT],NULL);
exit(0);
}
static void * thr_prime(void *p)
{
int i,j,mark;
i=((struct thr_arg_st *)p)->n;
free(p);//最好不要在这里free,最好和malloc在同一函数或是模块中。
mark=1;
for(j=2;j<i/2;j++)
{
if(i%j==0)
{
mark=0;
break;
}
}
if(mark)
printf("%d is a primer\n",i);
pthread_exit(NULL);
}
上面的代码,free和malloc不在一个函数里,下面代码做改进,用到了pthread_eixt()
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)
static void * thr_prime(void *p);
struct thr_arg_st
{
int n;
};
int main()
{
int i,err;
pthread_t tid[THRNUM];
struct thr_arg_st *p;
void * ptr;
for(i=LEFT;i<=RIGHT;i++)
{
p=malloc(sizeof(*p));
if(p==NULL)
{
perror("malloc()");
exit(1);
}
p->n=i;
err=pthread_create(tid+(i-LEFT),NULL,thr_prime,p);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
exit(1);
}
}
for(i=LEFT;i<=RIGHT;i++)
{
pthread_join(tid[i-LEFT],&ptr);
free(ptr);
}
exit(0);
}
static void * thr_prime(void *p)
{
int i,j,mark;
i=((struct thr_arg_st *)p)->n;
free(p);
mark=1;
for(j=2;j<i/2;j++)
{
if(i%j==0)
{
mark=0;
break;
}
}
if(mark)
printf("%d is a primer\n",i);
pthread_exit(p);
}
命令 ulimit -a可以看到栈的大小
一个进程可以创建多少的线程取决于资源量
下面用一个小例子,将竞争放大来看(在此例中,有20个线程出现,负责七手八脚的操作同一个文件)线程的动作都是一样的,都是打开文件,读数据,然后把数取出来加一覆盖写回去,最后把文件关闭。(这里面肯定会有竞争的出现)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THRNUM 20
#define FNAME "/tmp/out"
#define LINESIZE 1024
static void * thr_add(void *p)
{
FILE *fp;
char linebuf[LINESIZE];
fp=fopen(FNAME,"r+");
if(fp==NULL)
{
perror("fopen()");
exit(1);
}
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);//定位,要不然不是覆盖写回去了
fprintf(fp,"%d\n",atoi(linebuf)+1);
fclose(fp);
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i=0;i<THRNUM;i++)
{
err=pthread_create(tid+i,NULL,thr_add,NULL);
if(err)
{
fprintf(stderr,"pthread_create():%s\n",strerror(err));
}
}
for(i=0;i<THRNUM;i++)
pthread_join(tid[i],NULL);
exit(0);
}
初始阶段利用语句echo 1 >/tmp/out,将文件中的初始值设为1
运行结果:15(正确的话应该是21,表示20个线程都有加一)这就表明在运行过程中出现了竞争