筛质数的例子 201个进程。用指定n个进程筛质数。

cp ../../process_basic/primer0.c ./放到当前路径下

现在的计算范围,thrnum :right-left右边界-左边界

  • 思路:main当中,一个人干活 计算,现在希望每有一个待计算的i值用一个线程去做 for循环里的工作 用一个函数。main创建线程 兄弟 没有主次之分。
int main()
{
	int i,err;
	pthread_t tid[THRNUM]; //需要的参数 create
	for(i=LEFT;i<=RIGHT;i++)
	{
		err=pthread_create(&tid+(i-LEFT),NULL,thr_prime,&i);
		if(err)
		{
			fprintf(stderr,"pthread_create():%s\n",stderror(err));
			exit(1);  //join 收尸 如果 最后一个线程失败 需要将前面的回收资源
		}
	}
 
	//收尸
	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);
}
 
 

出现竞争 ,非原子操作。 协议 大家的约定。 十字路口 没有红绿灯,两辆车 南北 东西方向 车什么时候到来不知道 异步事件 什么 竞争:在没有约定的情况下 大家在抢同一个资源在用。十字路口 资源 两辆车 不知道是否相撞 无法预料。如何让两辆车不相撞? 最好不要用sleep 无法解决两个问题 等什么 等多久; 哲学问题 那如何让两辆车相撞?加长车长度,sleep 调试手段让线程存在时间增长 等待 测试 。

ps ax -L

错误:地址传参,i 一块地址 用201个指针指向这一块空间 201个人在用同一个地址 传值 可以 丑陋的办法 强转 void* i

看是否有各种形式的退出。 并发:顺序不是 从小到大

./primer0 |wc -l


继续改进:不要强转 201个i在201个空间 捏一个结构体 考虑动态分配 传结构体类型指针

 
struct thr_arg_st
{
	int n;
};
 
 
for
struct thr_arg_st *p;
 
p=malloc(sizeof(*p));
if(p==NULL)
{
	perror("malloc()");
	exit(1);
}
p->n=i;
err=pthread_create(tid+(i-LEFT),NULL,thr_prime,p);
 
 
i = (struct thr_arg_st*)p->n;
free(p);

但这样做也不好,希望malloc和free在用一个函数当中 或者同一个模块

改 pthread_join pthread_exit 传p

void *ptr;
for(i=LEFT;i<=RIGHT;i++)
{
	pthread_join(tid[i-LEFT],&ptr);
	free(ptr)
}
 
 
---
 
pthread_exit(p);

一个进程中能够创建出的线程个数? 一个函数扔出去很多次,代码段公用 栈独立 ulimt -a 栈 大小 虚拟空间大小,需要看当前空间里可以创建多少10m的栈。取决于外在的资源量。64位 是tid先 消耗掉。128t

资源数 有上限。


  • main负责创建20个线程,threadnum
  • 扔出去20个线程运行,相应的收尸环节
  • 每一个线程完成的任务 thr_add
  • 提前把1放到/tmp/out文件中去 使用命令echo 1 > /tmp/out 使用 cat 查看
  • atoi字符转为整型
  • sleep(1) 放大竞争,两辆车相撞的机率,一开始不大,而我们把机身拉长。。。
#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);
 
	//放大故障,竞争
	sleep(1);
 
	fprintf(fp,“%d\n”atoi(linebuf)+1);
	fclose(fp);
 
	pthread_exit(NULL);
}
 
int main()
{
	//线程标识数组
	pthread_t tid[THRNUM];
 
	//for循环创建 调用函数创建
	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));
			exit(1);
		}
	}
 
	for(i=0;i<THRNUM;i++)
		pthread_join(tid[i],NULL);
 
	exit(0);
}

  • mutex的创建和销毁,限制文件的操作是互斥的
  • 加入lock lock限制代码能否运行
//互斥量
static pthread_mutex_t mut = PTHREAD_MUTEXINITIALIZER;
 
pthread_mutext_lock(&mut);
/*
临界区
*/
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1);
fclose(fp);
pthread_mutex_unlock(&mut);
 
//销毁
pthread_mutex_destroy(&mut);

题目:四个线程,分别输出abcd,拼命打印,公正

  • thrnum 线程数量的限制
  • 收尸 tid
  • 创建与收尸
  • 拼命打印 while
  • 传递参数 i 0 1 2 3 控制所输出的character (void *)p
  • 使用信号 alarm ; 5秒后被杀死
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
 
#define THRNUM 4
 
static void *thr_func(void *p)
{
	int c='a'+(int)p;
	while(1)
		write(1,&c,1);//往终端打印
	pthread_exit();
}
int main()
{
	pthread_t tid[THRNUM];
	for(i=0;i<THRNUM;i++)
	{
		err = pthread_create(tid+i,NULL,thr_func,(void *)i);
		if(err)
		{
			//如果失败,报错结束
			fprintf(stderr,"pthrad_create():%s\n",strerror(err));
			exit(1);
		}
	}
 
	alarm(5);
 
	for(i=0;i<THRNUM;i++)
	{
		pthread_join(tid[i],NULL);
	}
	exit(0);
}
  • 用锁的机制,打印完a的去解锁b,让不能打印的一直阻塞在自己的锁的阶段。
  • 四个互斥量。创建时初始化 并加锁.pthread_mutex_init 初始化 四次循环 初始化四把锁 第二个参数 属性
  • 流程:初始化 锁上 添加线程
  • 打印的函数 原来上来while 1 死循环无条件地打印。先加上自己的锁 再打印
  • 在这里解下一个人 下一个锁是 mut+n+1 若为4的话 就是取0;但是不希望取模,用一个函数,next(n)
  • 加锁和解锁对应的对象是一段代码 而不是变量
static pthread_mutex_t mut[THRNUM]
 
for(i=0 ; i<= THRNUM ; i++)
{
	pthread_mutex_init(mut+i,NULL);
	pthread_mutex_lock(mut+i);
 
	err=pthread_create(tid+i,NULL,thr_func,(void *)i);
	if (err)
}
 
pthread_mutex_unlock(mut+0);//打印a的解锁
alarm(5)
 
// thr_func
 
int n=(int)p;
int c = 'a'+n;
while(1)
{
 
	//锁自己,解锁下一个 锁 n自己
	pthread_mutex_lock(mut+n);
	write(1,&c,1);
	pthread_mutex_unlock(mut+next(n));
}
 
 
static int next (int n)
{
	if ( n+1 == THRNUM) //也就是等于4了
		return 0;
	retuen n+1;
}
 

  • 池 ,上游下发任务,把任务做成任务池,能者多劳,最大限度利用当前的资源
  • 给num 做特殊值 - 当num >0 认为是待计算的任务 - 当num=0 说明无任务为空,当上游发现是0,就把下一个任务发下来。- 特殊环节,num=-1, 退出 提醒下游线程退出;上游线程等着收尸 用互斥量,加锁再枪
  • 需要一个全局变量, num
  • 不能用if判断,用while判断 num是否为0
#include<pthread.h>
 
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM 4
 
static int num = 0;
static pthread_mutex_t mut_num = PTHREAD_MUTEX_INITIALIZER;
 
static void *thr_prime(void *p);
 
int main()
{
	int i,err;
	pthread_t tid[THRNUM];
 
	for(i=0; i <= THRNUM; i++)
	{
		err = pthread_create(tid+(i-LEFT),NULL,thr_prime,(void *)i);
		if(err)
		{
			fprintf(stderr,"pthread_create():%s\n",strerr);
			exit(1);
		}
	}
 
	//下发任务环节
	for(i = LEFT; i<= RIGHT; i++)
	{
		pthread_mutex_lock(&mut_num);
		while(num != 0)
		{
			pthread_unlock(&mut_num);
			sched_yield(); //出让调度器给别的线程,非常短的sleep,不会出现状态颠簸(阻塞)。短的等待
			pthread_lock(&mut_num);
		}
		num = i;
		pthread_mutex_unlock(&mut_num);
	}
	num=-1;
 
 
	//收尸
	for(i=0 ; i <= THRNUM; i++)
		pthread_join(tid[i],NULL);
 
	pthread_mutex_destroy(&mut_num);
}
 
 
static void *thr_prime(void *p)
{
	int i,j,mark;
 
	pthread_mutex_lock(&mut_num);
	while(num==0)
	{
		pthread_
	}
}
 

todo 只能说锁很考验了。。。


多线程令牌桶的实现 mytbf

把原来的用信号实现的改写成用多线程实现 并发版本

mytbf_mt文件夹下面;

makefile

CFLAGS+=-pthread
LDFLAGS+=-pthread
 
all:mytbf
 
mytbf:main.o mytbf.o
	gcc $^ -o $@ $(CFLAGS) $(LDFLAGS)
 
clean:
	rm -rf *.o mytbf

vim * -p 打开,翻页 工具 gt 下一个标签页 pages

mytbf.h

声明

#ifndef MYTBF_H__
#define MYTBF_H__
 
#define MYTBF_MAX    1024
tydef void mytbf_t;
 
mytbf_t *mytbf_init(int cps,int burst);
 
int mytbf_fetchtoken(mytbf_t *,int );
 
int mytbf_returntoken(mytbf_t *,int );
 
int mytbf_destory(mytbf_t *);
 
#endif

mytbf.c

  • 完成四个函数
  • 困难的地方在于 如何发出第一个alarm信号和给signal alarm信号正确的行为, init 中调用module_load()
  • 希望有类似于c++构造函数使用特点出现,在init当中构造这样的内容
#include <signal.h>
 
#include "mytbf.h"
 
typedef void (*sighandler_t)(int);
 
static struct mytbf_st* job[MYTBF_MAX];
static int inited = 0;
static sighandler_t alrm_handler_save;
 
struct mytbf_st
{
	int cps;
	int burst;
	int token;
	int pos;
}
  • 想法是不要把过多的内容交给用户来处理