线程学习二(线程取消、分离、竞争)

线程取消选项

一个线程在运用的过程中一般都会用到线程取消
比如说一棵二叉树,查找某个结点,一个查找太累,用多个线程进项查找,会有一个找到,那么其他的线程就需要线程取消,然后
在收尸。正在运行的线程是无法收尸收回来的
函数
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个线程都有加一)这就表明在运行过程中出现了竞争

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值