C语言:高级并发操作(线程)

一、线程的概念

线程:进程中的一个实体,是CPU调度和分派的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器、一组寄存器和栈),但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行。线程在运行中呈现间断性。(以上来自《计算机四级教程——操作系统原理》)

谈到线程,就有必要说说进程的定义:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。(以上来自《计算机四级教程——操作系统原理》)

进程的定义有点绕口,我们看看进程由什么组成:程序、数据和进程控制块。其中程序,对应进程定义中“具有一定独立功能的程序”,但是进程除了程序本身,还需要有数据(可以理解为资源),以及,进程控制块。数据和进程控制块是程序运行时必不可少的资源,程序依赖这些资源进行相应的活动,就是我们说的“进程”了。

进程的两个基本属性:

进程是一个可拥有资源的独立单位;
进程是一个可以独立调度和分派的基本单位。
线程建立之初,就是为了将进程的上述两个属性分开,线程构成了“CPU调度和分派的基本单位”,这样一个进程中可以有很多线程,操作系统对线程进行调度和分派,可以更好地实现进程的并打执行;同时同一个进程下的线程可以共享该进程的全部资源,可以满足同一个进程下不同线程对进程资源的访问。线程的出现,巧妙地将进程的两个属性分开,使得进程可以更好地处理并行执行的需求。

线程就是一个正在运行的函数。posix线程是一套标准,而不是一套实现。还有别的标准如:openmp线程。
线程标识:pthread_t (不知道具体的内容,各家实现不同,linux下是int)
px axm命令 看到进程和线程--代表进程下的线程。 px ax -L查看轻量级线程。        

       int pthread_equal(pthread_t t1, pthread_t t2); 比较两个线程的ID号。相同返回非0,不同返回0.
       pthread_t pthread_self(void); 获取当前线程的线程ID

二、线程的创建

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);
线程的调度取决与调度器的策略。

create1.c

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>void* myfunc(void *p)
{puts("Thread is run!");printf("thread %ld \n",pthread_self());return NULL;
}int main()
{puts("Begin!");pthread_t tid;int ret;ret = pthread_create(&tid,NULL,myfunc ,NULL);if(ret){fprintf(stderr,"%s \n",strerror(ret));exit(1);}printf("main %ld \n",pthread_self());puts("End!");
}

线程的终止

        1.线程从启动例程返回,返回值就是线程的退出码。
        2. 线程可以被同一进程中的其他线程取消。
        3.线程调用pthread_exit()函数。       void pthread_exit(void *retval);

       int pthread_join(pthread_t thread, void **retval); 相当于进程的wait,用于收尸。

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>void* myfunc(void *p)
{puts("Thread is run!");pthread_exit(NULL);//线程专用清理函数。
//    return NULL;
}int main()
{puts("Begin!");pthread_t tid;int ret;ret = pthread_create(&tid,NULL,myfunc ,NULL);if(ret){fprintf(stderr,"%s \n",strerror(ret));exit(1);}pthread_join(tid,NULL); //收尸puts("End!");
}

栈的清理

pthread_cleanup_push(); //相当于atexit
pthread_cleanup_pop(); //相当于可以主动取数据。

       void pthread_cleanup_push(void (*routine)(void *),  是宏的实现,gcc -E查看预处理
                                 void *arg);
       void pthread_cleanup_pop(int execute); //选择是否调用。必须成对出现,用宏实现

cleanup.c

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>void cleanup_fun(void*p)
{puts(p);
}void* myfunc(void *p)
{puts("Thread is run!");pthread_cleanup_push(cleanup_fun,"cleanup:1");pthread_cleanup_push(cleanup_fun,"cleanup:2");pthread_cleanup_push(cleanup_fun,"cleanup:3");puts("push over!");pthread_exit(NULL);//线程专用清理函数。
//    return NULL;pthread_cleanup_pop(1) //线程退出后,全部都会调用;pthread_cleanup_pop(0);pthread_cleanup_pop(1);
}int main()
{puts("Begin!");pthread_t tid;int ret;ret = pthread_create(&tid,NULL,myfunc ,NULL);if(ret){fprintf(stderr,"%s \n",strerror(ret));exit(1);}pthread_join(tid,NULL); //收尸puts("End!");
}

线程的取消选项

正在运行的线程要是想要收尸收回来,那么就需要先进行取消(pthread_cancel)在进行收尸(pthread_join)。

       线程取消:int pthread_cancel(pthread_t thread);
        取消有两种状态:允许和不允许。
        不允许取消:继续执行代码,不受任何影响。
        允许取消又分为:异步cancel,和推迟cancel(默认)->推迟到cancel点在响应。
        cancal点:Posix定义的cancel点,都是可能引发堵塞的系统调用。
        pthread_setcancelstate:可以设置取消状态。
        pthread_setcanceltype:可以设置取消方式。
        pthread_testcancel:函数什么都不做,就是取消点。

线程分离:       int pthread_detach(pthread_t thread);

  动态模块单次初始化函数:int pthread_once(pthread_once_t *once_control,
           void (*init_routine)(void));
       pthread_once_t once_control = PTHREAD_ONCE_INIT;
 

     实例1
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; 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));}}for(i=LEFT;i<=RIGHT;i++){pthread_join(tid[i-LEFT],NULL);}return 0;
}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);return NULL;}  

以上代码运行会出现竞争的现象。因为传递参数用的是地址传参,数据需要取*才能拿到,不能保证上一个线程是否进行了该操作,最简单的是使用值传递。

primer0.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =LEFT;i<=RIGHT;i++){err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);// err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}for(i=LEFT;i<=RIGHT;i++){pthread_join(tid[i-LEFT],NULL);}return 0;
}void* thr_prime(void*p)
{int i,j,mark;i = (int)p;// 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);return NULL;}  

 primer0_e.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)struct thr_arg_st
{int n;
};void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err;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); // p就是结构体指针就是n的地址// err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}//free 不能在这里free,必须取走数据在free}for(i=LEFT;i<=RIGHT;i++){pthread_join(tid[i-LEFT],&ptr);// 收尸并且接受返回参数。free(ptr);}return 0;
}void* thr_prime(void*p)
{int i,j,mark;i = ((struct thr_arg_st*)p)->n;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); //返回值返回preturn NULL;}  
实例2 

add.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define FILENAME  "/tmp/out"
#define THRNUM (20)void* thr_add(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int 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);}return 0;
}void* thr_add(void*p)
{FILE*fp;char line_buf[1024];int len_size = 1024;fp = fopen(FILENAME,"r+");fgets(line_buf,len_size,fp);fseek(fp,0,SEEK_SET);fprintf(fp,"%d \n",atoi(line_buf)+1);fclose(fp);pthread_exit(NULL);return NULL;}  

二十个线程同时在一个文件中读数据写数据时会出现竞争和冲突。一个线程还没有写进入时,另一个线程读到了上次的数据。 

mytbf.c
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>#include "mytbf.h"struct mytbf_st
{int cps;int burst;int token;int pos;pthread_mutex_t mut;
};
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_t tid_alrm;
pthread_once_t init_once = PTHREAD_ONCE_INIT;static struct mytbf_st* job[MYTBF_MAX];typedef void (*sighandler_t)(int);static int get_free_pos_unlocked(void)
{for(int i=0;i< MYTBF_MAX;i++){if(job[i]==NULL)return i;}return -1;
}static void*  thr_alrm(void*p)
{while(1){pthread_mutex_lock(&mut_job);for(int i=0;i<MYTBF_MAX;i++){if(job[i] != NULL){pthread_mutex_lock(&job[i]->mut);job[i]->token += job[i]->cps;if(job[i]->token >job[i]->burst ){job[i]->token = job[i]->burst;}pthread_mutex_unlock(&job[i]->mut);}}pthread_mutex_unlock(&mut_job);sleep(1);}return NULL;
}static void module_unload()
{pthread_cancel(tid_alrm);pthread_join(tid_alrm,NULL);//只能一个人掉,二个人调用容易出差for(int i=0;i<MYTBF_MAX;i++){if(job[i]!=NULL){mytbf_destroy(job[i]);}}pthread_mutex_destroy(&mut_job);}static void module_load()
{int err;err = pthread_create(&tid_alrm,NULL,thr_alrm,NULL);if(err){fprintf(stderr,"create error\n");exit(1);}atexit(module_unload);
}mytbf_t* mytbf_init(int cps ,int burst)  //C语言中,void*可以赋值给任何类型的指针,任何类型的指针也都可以赋值给void*
{struct mytbf_st*me;int pos;pthread_once(&init_once,module_load); //只初始化一次me = malloc(sizeof(*me));if(me == NULL)return NULL;me->cps = cps;me->burst = burst;me->token = 0;pthread_mutex_init(&me->mut,NULL);pthread_mutex_lock(&mut_job);pos = get_free_pos_unlocked();if(pos < 0){pthread_mutex_unlock(&mut_job);free(me);return NULL;}me->pos = pos;job[pos] = me;pthread_mutex_unlock(&mut_job);return me;}
int mytbf_fetchtoken(mytbf_t*ptr,int size)  //获取token
{if(size <= 0)return -EINVAL;  //参数非法struct mytbf_st*me = ptr;pthread_mutex_lock(&me->mut);while(me->token <= 0 )  //token为空就等待{pthread_mutex_unlock(&me->mut);sched_yield();pthread_mutex_lock(&me->mut);}int n = (me->token>size?size:me->token);me->token -= n;pthread_mutex_unlock(&me->mut);return n;
}int mytbf_returntoken(mytbf_t*ptr,int size)  //返还token
{if(size<=0)return -EINVAL;struct mytbf_st*me = ptr;pthread_mutex_lock(&me->mut);me->token+= size;if(me->token > me->burst)me->token  = me->burst;pthread_mutex_unlock(&me->mut);return size;
}int mytbf_destroy(mytbf_t*ptr)
{struct mytbf_st *me;me = ptr;pthread_mutex_lock(&mut_job);job[me->pos] = NULL;pthread_mutex_unlock(&mut_job);pthread_mutex_destroy(&me->mut);free(ptr);return 0;}

三、线程同步

互斥量

相当于一把锁,必须先进行解锁才能操作。(查询法)
如果man pthread_mutex_init报错,请安装依赖:
sudo apt-get install manpages-posix manpages-posix-dev

       int pthread_mutex_destroy(pthread_mutex_t *mutex); //销毁锁
       int pthread_mutex_init(pthread_mutex_t *restrict mutex, 
           const pthread_mutexattr_t *restrict attr);  动态初始化
       pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  静态初始化

       int pthread_mutex_lock(pthread_mutex_t *mutex); //加锁
       int pthread_mutex_trylock(pthread_mutex_t *mutex);//尝试加锁,抢不上就继续执行
       int pthread_mutex_unlock(pthread_mutex_t *mutex);//解锁

add.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define FILENAME  "/tmp/out"
#define THRNUM (20)pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;void* thr_add(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int 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);}pthread_mutex_destroy(&mut);    return 0;
}void* thr_add(void*p)
{FILE*fp;char line_buf[1024];int len_size = 1024;pthread_mutex_lock(&mut);fp = fopen(FILENAME,"r+");fgets(line_buf,len_size,fp);fseek(fp,0,SEEK_SET);fprintf(fp,"%d \n",atoi(line_buf)+1);fclose(fp);pthread_mutex_unlock(&mut);pthread_exit(NULL);return NULL;}  

abcd.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define FILENAME  "/tmp/out"
#define THRNUM (4)pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;void* thr_abcd(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =0;i<THRNUM;i++){err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}alarm(2);for(i=0;i<THRNUM;i++){   pthread_join(tid[i],NULL);}pthread_mutex_destroy(&mut);    return 0;
}void* thr_abcd(void*p)
{int c = 'a'+ (int)p;while(1){write(1,&c,1);}pthread_exit(NULL);return NULL;}  

 abcd.c
使用锁链进行加锁解锁。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define FILENAME  "/tmp/out"
#define THRNUM (4)pthread_mutex_t mut[THRNUM];void* thr_abcd(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =0;i<THRNUM;i++){pthread_mutex_init(mut+i,NULL); //初始化四个锁pthread_mutex_lock(mut+i);err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}pthread_mutex_unlock(mut+0);alarm(2);for(i=0;i<THRNUM;i++){   pthread_join(tid[i],NULL);}pthread_mutex_destroy(&mut);    return 0;
}
int next(int n)
{if(n +1 ==THRNUM)return 0;return n+1;
}
void* thr_abcd(void*p)
{int c = 'a'+ (int)p;int n = (int)p;while(1){pthread_mutex_lock(mut+n);write(1,&c,1);pthread_mutex_unlock(mut+next(n) );}pthread_exit(NULL);return NULL;}  

 池类算法实现算质数(查询法)

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =LEFT;i<=RIGHT;i++){err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);// err= pthread_create(tid+(i-LEFT),NULL,thr_prime,&i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}for(i=LEFT;i<=RIGHT;i++){pthread_join(tid[i-LEFT],NULL);}return 0;
}void* thr_prime(void*p)
{int i,j,mark;i = (int)p;// 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);return NULL;}  

 条件变量

通知法进行通信。

   int pthread_cond_destroy(pthread_cond_t *cond);
       int pthread_cond_init(pthread_cond_t *restrict cond, 
           const pthread_condattr_t *restrict attr);
       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
       int pthread_cond_broadcast(pthread_cond_t *cond); //叫醒所有的等待
       int pthread_cond_signal(pthread_cond_t *cond);//叫醒任意一个等待
       int pthread_cond_timedwait(pthread_cond_t *restrict cond, //超时等待
           pthread_mutex_t *restrict mutex,
           const struct timespec *restrict abstime);
       int pthread_cond_wait(pthread_cond_t *restrict cond, //死等
           pthread_mutex_t *restrict mutex);

mytbf.c(通知法)

#include <stdlib.h>
#include <stdio.h>
#include <error.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>#include "mytbf.h"struct mytbf_st
{int cps;int burst;int token;int pos;pthread_mutex_t mut;pthread_cond_t cond;};
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER;
static pthread_t tid_alrm;
pthread_once_t init_once = PTHREAD_ONCE_INIT;static struct mytbf_st* job[MYTBF_MAX];typedef void (*sighandler_t)(int);static int get_free_pos_unlocked(void)
{for(int i=0;i< MYTBF_MAX;i++){if(job[i]==NULL)return i;}return -1;
}static void*  thr_alrm(void*p)
{while(1){pthread_mutex_lock(&mut_job);for(int i=0;i<MYTBF_MAX;i++){if(job[i] != NULL){pthread_mutex_lock(&job[i]->mut);job[i]->token += job[i]->cps;if(job[i]->token >job[i]->burst ){job[i]->token = job[i]->burst;}pthread_cond_broadcast(&job[i]->cond);pthread_mutex_unlock(&job[i]->mut);}}pthread_mutex_unlock(&mut_job);sleep(1);}return NULL;
}static void module_unload()
{pthread_cancel(tid_alrm);pthread_join(tid_alrm,NULL);//只能一个人掉,二个人调用容易出差for(int i=0;i<MYTBF_MAX;i++){if(job[i]!=NULL){mytbf_destroy(job[i]);}}pthread_mutex_destroy(&mut_job);}static void module_load()
{int err;err = pthread_create(&tid_alrm,NULL,thr_alrm,NULL);if(err){fprintf(stderr,"create error\n");exit(1);}atexit(module_unload);
}mytbf_t* mytbf_init(int cps ,int burst)  //C语言中,void*可以赋值给任何类型的指针,任何类型的指针也都可以赋值给void*
{struct mytbf_st*me;int pos;pthread_once(&init_once,module_load); //只初始化一次me = malloc(sizeof(*me));if(me == NULL)return NULL;me->cps = cps;me->burst = burst;me->token = 0;pthread_mutex_init(&me->mut,NULL);pthread_cond_init(&me->cond,NULL);	pthread_mutex_lock(&mut_job);pos = get_free_pos_unlocked();if(pos < 0){pthread_mutex_unlock(&mut_job);free(me);return NULL;}me->pos = pos;job[pos] = me;pthread_mutex_unlock(&mut_job);return me;}
int mytbf_fetchtoken(mytbf_t*ptr,int size)  //获取token
{if(size <= 0)return -EINVAL;  //参数非法struct mytbf_st*me = ptr;pthread_mutex_lock(&me->mut);while(me->token <= 0 )  //token为空就等待{pthread_cond_wait(&me->cond,&me->mut); //解锁等待,等待conad_broadcast和conad_signal的到来/*pthread_mutex_unlock(&me->mut);sched_yield();pthread_mutex_lock(&me->mut);*/}int n = (me->token>size?size:me->token);me->token -= n;pthread_mutex_unlock(&me->mut);return n;
}int mytbf_returntoken(mytbf_t*ptr,int size)  //返还token
{if(size<=0)return -EINVAL;struct mytbf_st*me = ptr;pthread_mutex_lock(&me->mut);me->token+= size;if(me->token > me->burst)me->token  = me->burst;pthread_cond_broadcast(&me->cond);pthread_mutex_unlock(&me->mut);return size;
}int mytbf_destroy(mytbf_t*ptr)
{struct mytbf_st *me;me = ptr;pthread_mutex_lock(&mut_job);job[me->pos] = NULL;pthread_mutex_unlock(&mut_job);pthread_mutex_destroy(&me->mut);pthread_cond_destroy(&me->cond);free(ptr);return 0;}

 primer0_pool.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sched.h>#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (4)static  int num = 0;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =0;i<=THRNUM;i++){err= pthread_create(tid+(i),NULL,thr_prime,(void *)i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}//下发任务for(i=LEFT;i<RIGHT;i++){pthread_mutex_lock(&mut);while(num !=0)  //不是0就需要等待任务被取走{pthread_cond_wait(&cond,&mut);}num = i; //下发任务pthread_cond_signal(&cond); //下游叫醒任意一个pthread_mutex_unlock(&mut);}pthread_mutex_lock(&mut);while(num!= 0){pthread_mutex_unlock(&mut);sched_yield(); //出让调度器给别的线程}num = -1; //用于线程退出pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mut);for(i=0;i<=THRNUM;i++){pthread_join(tid[i],NULL);}pthread_mutex_destroy(&mut);    pthread_cond_destroy(&cond);    return 0;
}void* thr_prime(void*p)
{int i,j,mark;while(1){pthread_mutex_lock(&mut);while(num == 0){pthread_cond_wait(&cond,&mut);}if(num == -1){pthread_mutex_unlock(&mut); //走到这里必须要解锁。break;}i= num;    num = 0;pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mut);mark = 1;for(j=2;j<i/2;j++){if(i%j ==0){mark = 0;break;}}if(mark)printf("[%d]%d is a primer \n",(int)p,i);}pthread_exit(NULL);return NULL;}  

abcd_cond.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>#define FILENAME  "/tmp/out"
#define THRNUM (4)pthread_mutex_t mut  = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int num;void* thr_abcd(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; for(i =0;i<THRNUM;i++){err= pthread_create(tid+(i),NULL,thr_abcd,(void*)i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}alarm(2);for(i=0;i<THRNUM;i++){   pthread_join(tid[i],NULL);}pthread_cond_destroy(&cond);pthread_mutex_destroy(&mut);    return 0;
}
int next(int n)
{if(n +1 ==THRNUM)return 0;return n+1;
}
void* thr_abcd(void*p)
{int c = 'a'+ (int)p;int n = (int)p;while(1){pthread_mutex_lock(&mut);while(num != n){pthread_cond_wait(&cond,&mut);}write(1,&c,1);num = next(num);pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mut );}pthread_exit(NULL);return NULL;}  

 信号量

互斥量是bool类型,信号量(semaphore)是int类型,使用的时候进行自减,不够就等待。

mysem.c

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include "mysem.h"struct mysem_st
{int value;pthread_mutex_t mut;pthread_cond_t cond;};mysem_t* mysem_init(int initval)
{struct mysem_st*me;me = malloc(sizeof(*me));if(me==NULL)return NULL;me->value = initval;pthread_mutex_init(&me->mut,NULL);pthread_cond_init(&me->cond,NULL);return me;}int mysem_add(mysem_t*ptr ,int n)
{struct mysem_st*me = ptr;pthread_mutex_lock(&me->mut);me->value+= n;pthread_cond_broadcast(&me->cond);pthread_mutex_unlock(&me->mut);return n;
}int mysem_sub(mysem_t*ptr ,int n )
{struct mysem_st*me = ptr;pthread_mutex_lock(&me->mut);while(me->value <n){pthread_cond_wait(&me->cond,&me->mut);}me->value -=n;pthread_mutex_unlock(&me->mut);return n;
}void  mysem_destroy(mysem_t*ptr)
{struct mysem_st*me = ptr;pthread_mutex_destroy(&me->mut);pthread_cond_destroy(&me->cond);free(me);
}

mysem.h 

#ifndef MYSEM_H
#define MYSEM_Htypedef void mysem_t;mysem_t* mysem_init(int initval);int mysem_add(mysem_t*,int);int mysem_sub(mysem_t*,int);void mysem_destroy(mysem_t*);#endif

 main.c

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "mysem.h"#define LEFT  30000000
#define RIGHT 30000200
#define THRNUM (RIGHT-LEFT+1)#define N 4
static mysem_t* sem;void* thr_prime(void*p);int main()
{pthread_t tid[THRNUM];int i,j,mark;int err; sem = mysem_init(N);if(sem ==NULL){fprintf(stderr,"mysem_init \n");exit(1);}for(i =LEFT;i<=RIGHT;i++){mysem_sub(sem,1);err= pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);if(err){fprintf(stderr,"pthread_create():%s\n",strerror(err));}}for(i=LEFT;i<=RIGHT;i++){pthread_join(tid[i-LEFT],NULL);}mysem_destroy(sem);   return 0;
}void* thr_prime(void*p)
{int i,j,mark;i = (int)p;// 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);sleep(5); //ps ax -L 可以观察到对线程进行了限制,只创建了四个线程mysem_add(sem,1);pthread_exit(NULL);return NULL;}  

makefile

all:mysem
CFLAGS+=-g -Wall -pthread
LDFLAGS+= -pthreadmysem:main.o mysem.ogcc $^ $(CFLAGS)	$(LDFLAGS) -o $@ clean:rm -rf *.o mysem

读写锁

互斥量和信号量的综合使用。分为读锁(信号量)和写锁(互斥量)。一般读写要设置上限。

需要防止写者饿死的情况发生。

四、线程相关属性

pthread_create第二个参数是线程的属性。

       int pthread_attr_init(pthread_attr_t *attr);
       int pthread_attr_destroy(pthread_attr_t *attr);

测试程序创建最大线程个数。()

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>void* func(void)
{int i;//    printf("%p\n",&i);pthread_exit(NULL);return NULL;
}int main()
{int err;pthread_t tid;pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_setstacksize(&attr,1024*1024); //1mbint i = 0;for(;;i++){err = pthread_create(&tid,&attr,func,NULL);if(err){fprintf(stderr,"create err\n");break;}}printf("max = %d \n",i);pthread_attr_destroy(&attr);return 0;
}

线程同步的属性

互斥量属性:

       int pthread_mutexattr_init(pthread_mutexattr_t *attr);
       Refer to pthread_mutexattr_destroy().
        int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, //跨进程起作用
                                        int *pshared);
       int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,
                                        int pshared);

//创建一个子进程,可以共享文件描述符数组.也可以选择不共享。linux下不区分进程和线程
       int clone(int (*fn)(void *), void *stack, int flags, void *arg, ... 
                 /* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
       int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,
           int *restrict type);
       int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

条件变量属性:       
       int pthread_condattr_destroy(pthread_condattr_t *attr);
       int pthread_condattr_init(pthread_condattr_t *attr);
读写锁属性:

五、重入

一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。

多线程中的IO。unlocked函数结尾的都是(不可重入函数,不支持多线程并发)。man putc_unlocked,查看不支持的IO操作。

线程与信号

       int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
       int sigwait(const sigset_t *set, int *sig);
       int pthread_kill(pthread_t thread, int sig);

openmp线程标准

参考官网:www.OpenMp.org

gcc4.0之后都支持openmp语法标记。有几个CPU就可以实现多少并发

hello.c

#include <stdio.h>
#include <stdlib.h>int main()
{
#pragma omp parallel  //实现并发
{puts("Hello ");puts(" World");
}return 0;
}

makefile

CFLAGS += -Wall -fopenmp

make hello编译,并且运行。

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>int main()
{
#pragma omp parallel  sections
{
#pragma omp sectionprintf("[%d:]Hello \n",omp_get_thread_num() );
#pragma omp sectionprintf("[%d:]World \n",omp_get_thread_num() );
}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/45171.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端文件下载的方式

方式一&#xff1a;a标签直接下载 <a href"链接" >下载</a>一个文件链接&#xff08;一般是服务器上的某个文件&#xff09;&#xff0c;这个链接一般地址栏输入是预览&#xff0c;不是附件下载 如果想改成附件下载&#xff0c;以下两种方式任选一个均…

【鸿蒙学习笔记】关系型数据库概述

目录标题 关系型数据库的运行机制样例代码共通方法 DBUtilsIndex 代码效果 关系型数据库的运行机制 1、 关系型数据库对应用提供通用的操作接口&#xff0c;底层使用SQLite作为持久化存储引擎&#xff0c;支持SQLite具有的数据库特性&#xff0c;包括但不限于事务、索引、视图…

自建邮件服务器有哪些方法步骤与注意事项?

自建邮件服务器如何设置解析&#xff1f;邮件服务器怎么使用&#xff1f; 自建邮件服务器可以为个人或企业提供更多的灵活性和控制权&#xff0c;然而&#xff0c;这也是一个复杂且需要谨慎处理的任务。AokSend将探讨自建邮件服务器的基本方法步骤和需要注意的事项。 自建邮件…

数据库(mysql)忘记密码解决办法

步骤一&#xff1a;先停止数据库服务 [rootGGB ~]# systemctl stop mysql.service [rootGGB ~]# systemctl status mysql.service ● mysql.service - MySQL ServerLoaded: loaded (/etc/systemd/system/mysql.service; enabled; vendor preset: disabled)Active: fail…

逻辑回归(纯理论)

1.什么是逻辑回归&#xff1f; 逻辑回归是一种常用的统计学习方法&#xff0c;主要用于解决分类问题。尽管名字中包含"回归"&#xff0c;但它实际上是一种分类算法 2.为什么机器学习需要使用逻辑回归 1.二元分类 这是逻辑回归最基本和常见的用途。它可以预测某个事…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【HMAC(C/C++)】

HMAC(C/C) HMAC是密钥相关的哈希运算消息认证码&#xff08;Hash-based Message Authentication Code&#xff09;&#xff0c;是一种基于Hash函数和密钥进行消息认证的方法。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生…

计算机SCI期刊,闭眼投,保证检索,命中率100%

一、期刊名称 Pervasive and Mobile Computing 二、期刊简介 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机 影响因子&#xff1a;3 中科院分区&#xff1a;3区 三、期刊简介 Pervasive and Mobile Computing Journal &#xff08;PMC&#xff09; 是一本高影响力…

基于前馈神经网络 FNN 实现股票单变量时间序列预测(PyTorch版)

前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…

自定义View-渐变TextView(重点:绘制文本)

源码链接 夸克网盘分享 效果展示 分析 动态效果&#xff0c;使用Animator实现自定义View 继承TextView使用TextView的测量&#xff0c;不重写使用TextView的布局&#xff0c;不重写绘制-重写绘制 使用两种颜色绘制文本颜色占比不同&#xff0c;百分比从0~1 实现 自定义属性…

Vue使用socket实现实时通信

一、新建socket文件 class SocketService {constructor() {this.socket null;this.reconnectTimer null;this.messageCallback null;this.connectionParams null;this.pathnull}init() {this.clearReconnectTimer(); // 尝试重新连接之前先清除重连定时器if (typeof WebSo…

论文发表作图必备:训练结果对比,多结果绘在一个图片【Precision】【Recall】【mAP0.5】【mAP0.5-0.95】【loss】

前言:Hello大家好,我是小哥谈。YOLO(You Only Look Once)算法是一种目标检测算法,它可以在图像中实时地检测和定位目标物体。YOLO算法通过将图像划分为多个网格,并在每个网格中检测目标物体,从而实现快速的目标检测。本文所介绍的作图教程适用于所有YOLO系列版本算法,接…

Go泛型详解

引子 如果我们要写一个函数分别比较2个整数和浮点数的大小&#xff0c;我们就要写2个函数。如下&#xff1a; func Min(x, y float64) float64 {if x < y {return x}return y }func MinInt(x, y int) int {if x < y {return x}return y }2个函数&#xff0c;除了数据类…

Idea在线搜索Maven依赖-好用工具分享

maven_search 等价于网页搜索maven依赖&#xff0c;非常方便快捷 下载安装后&#xff0c;使用&#xff1a; 点击上方Tools Maven Search 或者快捷键 Ctrl Shift M 最后选择依赖&#xff0c;复制即可

Vue 3 与 TypeScript:最佳实践详解

大家好,我是CodeQi! 很多人问我为什么要用TypeScript? 因为 Vue3 喜欢它! 开个玩笑... 在我们开始探索 Vue 3 和 TypeScript 最佳实践之前,让我们先打个比方。 如果你曾经尝试过在没有 GPS 的情况下开车到一个陌生的地方,你可能会知道那种迷失方向的感觉。 而 Typ…

昇思学习打卡-17-热门LLM及其他AI应用/基于MobileNetv2的垃圾分类

文章目录 网络介绍读取数据集训练训练策略模型保存损失函数优化器模型训练 网络介绍 MobileNetv2专注于移动端、嵌入式或IoT设备的轻量级CNN网络。MobileNet网络使用深度可分离卷积&#xff08;Depthwise Separable Convolution&#xff09;的思想在准确率小幅度降低的前提下&…

分享一款嵌入式开源LED指示灯控制代码框架cotLed

一、工程简介 cotLed是一款轻量级的LED控制软件框架&#xff0c;可以十分方便地控制及自定义LED的各种状态&#xff0c;移植方便&#xff0c;无需修改&#xff0c;只需要在初始化时实现单片机硬件GPIO初始化&#xff0c;同时为框架接口提供GPIO写函数即可。 框架代码工程地址&a…

Apache Dubbo与Nacos整合过程

Dubbo服务发现 Dubbo 提供的是一种 Client-Based 的服务发现机制&#xff0c;依赖第三方注册中心组件来协调服务发现过程&#xff0c;支持常用的注册中心如 Nacos、Consul、Zookeeper 等。 以下是 Dubbo 服务发现机制的基本工作原理图&#xff1a; 服务发现包含提供者、消费者…

【深度学习】图形模型基础(7):机器学习优化中的方差减少方法(2)

4.高级算法 本节将探讨基本变分减少&#xff08;VR&#xff09;方法的几种拓展。这些拓展旨在处理更广泛的应用场景&#xff0c;包括非光滑问题和/或非强凸问题。此外&#xff0c;一些拓展利用算法技巧或问题结构的特性&#xff0c;设计出比基础方法更高效的算法。 4.1. SGD与…

LabVIEW中使用 DAQmx Connect Terminals作用意义

该图展示了如何在LabVIEW中使用 DAQmx Connect Terminals.vi 将一个信号从一个源端口连接到一个目标端口。这种处理有以下几个主要目的和作用&#xff1a; 同步操作&#xff1a; 在多任务、多通道或多设备系统中&#xff0c;可能需要不同的组件在同一时刻执行某些操作。通过将触…

Windows下终端Kafka指令常用操作

1、创建Topic kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic test 2、查看Topic列表 kafka-topics.bat --list --bootstrap-server localhost:9092 3、设置Topic最大消息大小 kafka-topics.bat --bootstrap-s…