1.线程的概念
2.线程的创建
线程的终止
线程的清理
线程的取消选项
3.线程同步
4.线程属性
线程同步的属性
5. 重入
线程与信号
线程与fork
1.概念
一个正在运行的函数
posix线程是一套标准,而不是实现
openmp标准线程
线程标识:pthread_t
函数:
(1).pthread_equal 比较两个线程号
(2).pthread_self :获取线程号
2.线程的创建
函数:pthread_create
参数:1.回填标识;2.只读标识;3.函数入口地址;4:函数参数
返回值:
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
线程的调度取决于调度器的策略
收尸函数:
第二个参数为NULL表示只收尸不关心状态。
RETURN VALUE
On success, pthread_join() returns 0; on error, it returns an error number.
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<pthread.h>
static void* func(void*) {
puts("Thread is working!");
pthread_exit(NULL);
//return NULL;
}
int main() {
pthread_t tid;
int err;
puts("Begin!");
err = pthread_create(&tid, NULL, func, NULL);
if (err) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
int erro = pthread_join(tid, NULL);
if (erro) {
fprintf(stderr, "pthread_join(): %s\n", strerror(erro));
exit(1);
}
puts("End!");
exit(0);
}
//Begin!
//Thread is working!
//End!
3.线程的终止
3.1终止的3种方式:
1)线程从启动历程返回,返回值就是线程的退出码;
2) 线程可以被同一进程中的其他线程取消
3)线程调用pthread_exit()函数
pthread_cleanup_pop可以写在pthread_exit之后(执行到pthread_exit,还没有pop的默认执行pthread_cleanup_pop(1);//1表示调用,0表示不调用)
3.2栈的清理
函数:
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include<pthread.h>
static void cleanup_fuc(void* p) {
puts((const char*)p);
}
static void* func(void* p) {
puts("Thread is working!");
pthread_cleanup_push(cleanup_fuc, (void*)"cleanup:1");
pthread_cleanup_push(cleanup_fuc, (void*)"cleanup:2");
pthread_cleanup_push(cleanup_fuc, (void*)"cleanup:3");
//push和pop必须成对出现(因为这两个函数是宏定义的,一对大括号分别落在这两个函数中)
pthread_cleanup_pop(1);//1表示调用,0表示不调用
pthread_cleanup_pop(0);
pthread_cleanup_pop(1);
pthread_exit(NULL);
//return NULL;
}
int main() {
pthread_t tid;
int err;
puts("Begin!");
err = pthread_create(&tid, NULL, func, NULL);
if (err) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
pthread_join(tid, NULL);
puts("End!");
exit(0);
}
/*
Begin!
Thread is working!
cleanup:3
cleanup:1
End!
*/
4.线程的取消
函数:
RETURN VALUE
On success, pthread_cancel() returns 0; on error, it returns a nonzero error number.
线程的取消选项:允许和不允许
允许取消又分为:异步cancel和推迟cancel(默认)–>推迟到cancel点
cancel点:POSIX定义的cancel点,都是可能引发阻塞的系统调用
函数:
pthread_setcancelstate:设置是否允许取消
pthread_setcanceltype:设置取消方式
pthread_testcancel:本函数什么都不做,就是一个取消点
线程分离:
int pthread_detach(pthread_t thread);
5.线程——竞争实例
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
static void* thr_prime(void *i) {
int num = *((int*)i) ;
int mark = 1;
for (int j = 2; j < num / 2; j++) {
if (num % j == 0) {
mark = 0;
break;
}
}
if (mark)
printf("%d is a primer\n", num);
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
for (int 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 (int i = LEFT; i <= RIGHT; i++) {
pthread_join(tid[i - LEFT], NULL);//接收thr_prime返回的指针
}
exit(0);
}
结果:每次都不一样,正确应该是18个(发生竞争)
原因是:所有线程入口函数参数在共享地址i,前面的线程可能还没把i拿走,就创建了第二个线程。
改进:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
struct thr_arg_st {
int n;
};
static void* thr_prime(void *i) {
int num = ((struct thr_arg_st*)i) -> n;
int mark = 1;
for (int j = 2; j < num / 2; j++) {
if (num % j == 0) {
mark = 0;
break;
}
}
if (mark)
printf("%d is a primer\n", num);
pthread_exit(i); //记录返回状态为地址i
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
struct thr_arg_st * p = NULL;
void * ptr = NULL;
for (int i = LEFT; i <= RIGHT; i++) {
p = malloc(sizeof(*p)); //malloc
if(p == NULL) {
perror("malloc()");
exit(1);
}
p->n = i;
err = pthread_create(tid + i - LEFT, NULL, thr_prime, p);//p的地址不同了
if(err) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
}
for (int i = LEFT; i <= RIGHT; i++) {
pthread_join(tid[i - LEFT], &ptr);//接收thr_prime返回的指针
free(ptr); //free
}
exit(0);
}
/*
30000059 is a primer
30000023 is a primer
30000083 is a primer
30000163 is a primer
30000169 is a primer
30000079 is a primer
30000037 is a primer
30000109 is a primer
30000071 is a primer
30000041 is a primer
30000133 is a primer
30000049 is a primer
30000193 is a primer
30000199 is a primer
30000149 is a primer
30000137 is a primer
30000167 is a primer
30000001 is a primer
*/
6.竞争故障
有问题的代码:
初始值1,每个线程执行加1,正确应该是21
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define THRNUM 20
#define LINESIZE 1024
#define FNAME "/tmp/out"
//static pthread_mutex_t mut[THRNUM] ;
static void* thr_add(void *p) {
FILE* fp = fopen(FNAME,"r+");
char linebuf[LINESIZE];
if(fp == NULL) {
perror("fopen()");
exit(1);
}
fgets(linebuf, LINESIZE, fp);
fseek(fp, 0, SEEK_SET); //定位文件第一行数字
sleep(1); //所有线程停在这里, 读到的数字都是1
fprintf(fp, "%d\n", atoi(linebuf) + 1);
fclose(fp);
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
for (int 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 (int i = 0; i < THRNUM; i++) {
pthread_join(tid[i], NULL);//收尸
}
exit(0);
}
输出的是2
7.互斥量
函数:
pthread_mutex_init动态初始化
pthread_mutex_destroy
lock会一直等待,trylock不等
改进代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define THRNUM 20
#define LINESIZE 1024
#define FNAME "/tmp/out"
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER ;
static void* thr_add(void *p) {
FILE* fp = fopen(FNAME,"r+");
char linebuf[LINESIZE];
if(fp == NULL) {
perror("fopen()");
exit(1);
}
pthread_mutex_lock(&mut); //lock
fgets(linebuf, LINESIZE, fp);
fseek(fp, 0, SEEK_SET); //定位文件第一行数字
sleep(1); //停1s
fprintf(fp, "%d\n", atoi(linebuf) + 1);
fclose(fp);
pthread_mutex_unlock(&mut); //unlock
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
for (int 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 (int i = 0; i < THRNUM; i++) {
pthread_join(tid[i], NULL);//收尸
}
pthread_mutexattr_destroy(&mut);//销毁互斥量
exit(0);
}
实例2:
依次打印abcd循环5s
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define THRNUM 4
static pthread_mutex_t mut[THRNUM] ;
static void* thr_func(void *p) {
int n = (int)p;
char c = 'a' + n;
while(1) {
pthread_mutex_lock(mut + n); //锁住自己
write(1, &c, 1);
pthread_mutex_unlock(mut + (n + 1) % THRNUM); //松开下一个
}
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
for (int 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) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
}
pthread_mutex_unlock(mut + 0);//解开第一个
alarm(5); //5s后发出信号SIGALRM中断进程
for (int i = 0; i < THRNUM; i++) {
pthread_join(tid[i], NULL);//收尸
}
//pthread_mutexattr_destroy(&mut);//销毁互斥量
exit(0);
}
//输出:循环打印abcd, 5秒后终止
每次锁住自己,等上一个解开自己
8.池类写法(4个线程处理200个数)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#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;
//计算一个区间内的质数, 放入一个数num,4个线程抢着计算,取走数了num变为0,等计算完了再放下一个数,全部算完了num=-1
//num>0是任务放入一个数 0是这个数取走了等待放入下一个数 -1退出
static void* thr_prime(void *p) {
int i, j, mark;
while(1) {
pthread_mutex_lock(&mut_num);
while(num == 0) { //没有新任务(之前的数字取走了,新的数还没放进来)
pthread_mutex_unlock(&mut_num); //松开 ,让别人尽快放进来数
sched_yield();
pthread_mutex_lock(&mut_num);//加锁
}
if(num == -1) { //可能已经结束
pthread_mutex_unlock(&mut_num);//不能忘记unlock
break;
}
i = num;
num = 0;
pthread_mutex_unlock(&mut_num);
mark = 1;
for (int 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);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int err;
for (int 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));
exit(1);
}
}
for(int i = LEFT; i <= RIGHT; i++) {
pthread_mutex_lock(&mut_num);
while(num != 0) { //num是0才赋值
pthread_mutex_unlock(&mut_num); //松开,让别人有机会加锁(可能之前的数还没被取走,让别人尽快取走!)
sched_yield();//出让调度器给别的线程,可以理解为很短的sleep, 且不会造成当前进程的调度颠簸
pthread_mutex_lock(&mut_num);
}
num = i; //继续放入数
pthread_mutex_unlock(&mut_num);
}
pthread_mutex_lock(&mut_num);
while(num != 0) { //防止最后的数还没处理num就被写成-1
pthread_mutex_unlock(&mut_num); //松开
sched_yield();
pthread_mutex_lock(&mut_num);//加锁
}
num = -1; //退出
pthread_mutex_unlock(&mut_num);
for (int i = 0; i <= THRNUM; i++) {
pthread_join(tid[i], NULL);//接收thr_prime返回的指针
}
pthread_mutex_destroy(&mut_num);
exit(0);
}
结果:
能者多劳,哪个线程抢到就哪个线程计算
改进之处:可以用通知法减少盲等
9.线程令牌桶
函数:pthread_once,保证一个函数只被调用一次
mtbf.h
#ifndef MYTBF_H__
#define MYTBF_H__
#define MYTBF_MAX 1024
typedef 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_destroy(mytbf_t *);
#endif
mytbf.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<pthread.h>
#include <unistd.h>
#include"mytbf.h"
#include<string.h>
static struct mytbf_st* job[MYTBF_MAX]; //结构体指针数组 自动全0
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER; //这个互斥量保证job数组以独占形式存在
static int inited = 0;
static pthread_t tid_alrm;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
struct mytbf_st {
int cps; //速率
int burst; //上限
int token;
int pos; //在job数组的位置
pthread_mutex_t mut; //这个互斥量保证token以独占形式存在(mytbf_fetchtoken和mytbf_returntoken一个对token减一个对token加容易发生竞争)
};
static void * thr_alrm(void* p) {
while (1) {
pthread_mutex_lock(&mut_job); //锁job数组
for (int i = 0; i < MYTBF_MAX; i++) {
if (job[i] != NULL) {
pthread_mutex_lock(&job[i]->mut);//锁token
job[i]->token += job[i]->cps; //每一秒加上每秒传输字节数CPS到token(每个token表示一字节)
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);//1s做一次
}
}
static void module_unload();
static void module_load() {
int err;
err = pthread_create(&tid_alrm, NULL, thr_alrm, NULL);
if (err) {
fprintf(stderr, "pthreda_create():%s\n", strerror(err));
exit(1);
}
atexit(module_unload); //复原
}
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]);
}
//free(job[i]);
}
pthread_mutex_destroy(&mut_job);
}
static int get_free_pos_unlocked() {
for (int i = 0; i < MYTBF_MAX; i++) {
if (job[i] == NULL)
return i;
return -1; //没空地了
}
}
static int min(int a, int b) {
return a < b ? a : b;
}
mytbf_t* mytbf_init(int cps, int burst) {
struct mytbf_st * me;
//if (!inited) {//保证只调用一次
// module_load();
// inited = 1;
//}
pthread_once(&init_once, module_load);//保证只调用一次
me = malloc(sizeof(*me));
if (me == NULL)
return NULL;
me->token = 0;
me->cps = cps;
me->burst = burst;
pthread_mutex_init(&me->mut, NULL);
//----------临界区--------------------
pthread_mutex_lock(&mut_job);
int 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) {
struct mytbf_st * me = ptr;//void* 转换成 struct mytbf_st *
if (size <= 0)
return -EINVAL; //参数非法
pthread_mutex_lock(&me->mut);
while (me->token <= 0) { //等到有token为止
pthread_mutex_unlock(&me->mut);
sched_yield(); //出让调度器
pthread_mutex_lock(&me->mut);
}
int n = min(me->token, size);
me->token -= n;
pthread_mutex_unlock(&me->mut);
return n;
}
int mytbf_returntoken(mytbf_t* ptr, int size) {
struct mytbf_st * me = ptr;//void* 转换成 struct mytbf_st *
if (size <= 0)
return -EINVAL; //参数非法
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 = ptr;
pthread_mutex_lock(&mut_job);
job[me->pos] = NULL;
pthread_mutex_unlock(&mut_job);
pthread_mutex_destroy(&me->mut);
free(ptr);
return 0;
}
main.c
#include<stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<errno.h>
#include<signal.h>
#include"mytbf.h"
#include <string.h>
#define CPS 10 //每秒10字节
#define BUFSIZE 1024
#define BURST 100 //上限,限制token值
int main(int argc, char** argv) {
int sfd, dfd = 1; //输出到标准输出
char buf[BUFSIZE];
int len, ret;
int pos = 0;
int size;
mytbf_t * tbf;
if (argc != 2) {
fprintf(stderr, "Usage:....\n");
exit(1);
}
//signal(SIGALRM, alrm_handler);
//alarm(1);
do {
sfd = open(argv[1], O_RDONLY);//不管真错,还是假错(信号中断),都返回-1
if (sfd < 0) {
if (errno != EINTR) {//不是信号打断系统调用,是真的错,直接退出,如果是假错,则继续open
perror("open()");
exit(1);
}
}
} while (sfd < 0);
tbf = mytbf_init(CPS, BURST);
if (tbf == NULL) {
fprintf(stderr, "mytbf_init() failed!\n");
exit(1);
}
while (1) {
size = mytbf_fetchtoken(tbf, BUFSIZE);
if (size < 0) {
fprintf(stderr, "mytbf_fetchtoken():%s\n", strerror(-size));
exit(1);
}
while ((len = read(sfd, buf, size)) < 0) {
if (errno == EINTR)//假错中断
continue;
perror("read()");
break;
}
if (len == 0) {//读完了
break;
}
if (size - len > 0) //需要归还
mytbf_returntoken(tbf, size - len);
pos = 0;
while (len > 0) {//防止真正写进去的数少于读进来的数
ret = write(dfd, buf + pos, len);//写入失败返回-1
if (ret < 0) {
///
if (errno == EINTR)//假错中断
continue;
///
perror("write()");
exit(1);
}
pos += ret;
len -= ret;
}
}
//close(dfd);
close(sfd);
mytbf_destroy(tbf);
exit(0);
}
10.条件变量
函数:
pthread_cond_init动态初始化
pthread_cond_destroy
pthread_cond_broadcast全通知
pthread_cond_signal只唤醒一个
pthread_cond_wait死等
pthread_cond_timewait
例子1
上面的线程令牌桶mytbf.c加上条件变量(非盲等版本):
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<pthread.h>
#include <unistd.h>
#include"mytbf.h"
#include<string.h>
static struct mytbf_st* job[MYTBF_MAX]; //结构体指针数组 自动全0
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER; //这个互斥量保证job数组以独占形式存在
static int inited = 0;
static pthread_t tid_alrm;
static pthread_once_t init_once = PTHREAD_ONCE_INIT;
struct mytbf_st {
int cps; //速率
int burst; //上限
int token;
int pos; //在job数组的位置
pthread_mutex_t mut; //这个互斥量保证token以独占形式存在(mytbf_fetchtoken和mytbf_returntoken一个对token减一个对token加容易发生竞争)
pthread_cond_t cond; //条件变量!!!!!
};
static void * thr_alrm(void* p) {
while (1) {
pthread_mutex_lock(&mut_job); //锁job数组
for (int i = 0; i < MYTBF_MAX; i++) {
if (job[i] != NULL) {
pthread_mutex_lock(&job[i]->mut);//锁token
job[i]->token += job[i]->cps; //每一秒加上每秒传输字节数CPS到token(每个token表示一字节)
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);//1s做一次
}
}
static void module_unload();
static void module_load() {
int err;
err = pthread_create(&tid_alrm, NULL, thr_alrm, NULL);
if (err) {
fprintf(stderr, "pthreda_create():%s\n", strerror(err));
exit(1);
}
atexit(module_unload); //复原
}
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]);
}
//free(job[i]);
}
pthread_mutex_destroy(&mut_job);
}
static int get_free_pos_unlocked() {
for (int i = 0; i < MYTBF_MAX; i++) {
if (job[i] == NULL)
return i;
return -1; //没空地了
}
}
static int min(int a, int b) {
return a < b ? a : b;
}
mytbf_t* mytbf_init(int cps, int burst) {
struct mytbf_st * me;
//if (!inited) {//保证只调用一次
// module_load();
// inited = 1;
//}
pthread_once(&init_once, module_load);//保证只调用一次
me = malloc(sizeof(*me));
if (me == NULL)
return NULL;
me->token = 0;
me->cps = cps;
me->burst = burst;
pthread_mutex_init(&me->mut, NULL);
pthread_cond_init(&me->cond, NULL);
//----------临界区--------------------
pthread_mutex_lock(&mut_job);
int 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) {
struct mytbf_st * me = ptr;//void* 转换成 struct mytbf_st *
if (size <= 0)
return -EINVAL; //参数非法
pthread_mutex_lock(&me->mut);
while (me->token <= 0) { //等到有token为止
// pthread_mutex_unlock(&me->mut);
// sched_yield(); //出让调度器
// pthread_mutex_lock(&me->mut);
pthread_cond_wait(&me->cond, &me->mut);//换成这一句,不再盲等(得到通知后先去抢锁,再看是否可以退出while,成立则继续运行)!!!
}
int n = min(me->token, size);
me->token -= n;
pthread_mutex_unlock(&me->mut);
return n;
}
int mytbf_returntoken(mytbf_t* ptr, int size) {
struct mytbf_st * me = ptr;//void* 转换成 struct mytbf_st *
if (size <= 0)
return -EINVAL; //参数非法
pthread_mutex_lock(&me->mut);
me->token += size;
if (me->token > me->burst) //大于上限
me->token = me->burst;
pthread_cond_broadcast(&me->cond);//还了cond后也通知一下 !!!
pthread_mutex_unlock(&me->mut);
return size;
}
int mytbf_destroy(mytbf_t *ptr) {
struct mytbf_st * 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;
}
例子2
池类写法,4个线程处理200个数的非盲等版本
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM 4
static int num = 0;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//!!!!!!!!!!!!!!!!!!!!!!!!!!!
static pthread_mutex_t mut_num = PTHREAD_MUTEX_INITIALIZER;
//计算一个区间内的质数, 放入一个数num,4个线程抢着计算,取走数了num变为0,等计算完了再放下一个数,全部算完了num=-1
//num>0是任务放入一个数 0是这个数取走了等待放入下一个数 -1退出
//下游函数
static void* thr_prime(void *p) {
int i, j, mark;
while (1) {
pthread_mutex_lock(&mut_num);
while (num == 0) { //没有新任务(之前的数字取走了,新的数还没放进来)
//pthread_mutex_unlock(&mut_num); //松开 ,让别人尽快放进来数
//sched_yield();
//pthread_mutex_lock(&mut_num);//加锁
pthread_cond_wait(&cond, &mut_num);
}
if (num == -1) { //可能已经结束
pthread_mutex_unlock(&mut_num);//不能忘记unlock
break;
}
i = num;
num = 0;
pthread_cond_broadcast(&cond);//!!!!!!!!!!!!!!!!!!!!!!!!!唤醒所有(以免只唤醒一个和自己一样在这个下游函数里的线程)
pthread_mutex_unlock(&mut_num);
mark = 1;
for (int 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);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int err;
for (int 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));
exit(1);
}
}
for (int i = LEFT; i <= RIGHT; i++) {
pthread_mutex_lock(&mut_num);
while (num != 0) { //num是0才赋值(可能还没被取走,还不能放入下一个数)
//pthread_mutex_unlock(&mut_num); //松开,让别人有机会加锁(可能之前的数还没被取走,让别人尽快取走!)
//sched_yield();//出让调度器给别的线程,可以理解为很短的sleep, 且不会造成当前进程的调度颠簸
//pthread_mutex_lock(&mut_num);
pthread_cond_wait(&cond, &mut_num); //!!!!!!!!!!!!!!!!!!!!!!!!!!
}
num = i; //继续放入数
pthread_cond_signal(&cond);//!!!!!!!!!!!!!!!!!!!!!!唤醒一个就行(唤醒下游函数任意一个就行)
pthread_mutex_unlock(&mut_num);
}
pthread_mutex_lock(&mut_num);
while (num != 0) { //防止最后的数还没处理num就被写成-1
//pthread_mutex_unlock(&mut_num); //松开
//sched_yield();
//pthread_mutex_lock(&mut_num);//加锁
pthread_cond_wait(&cond, &mut_num);
}
num = -1; //退出
pthread_cond_broadcast(&cond);//!!!!!!!!!!!!!!!!
pthread_mutex_unlock(&mut_num);
for (int i = 0; i <= THRNUM; i++) {
pthread_join(tid[i], NULL);//接收thr_prime返回的指针
}
pthread_mutex_destroy(&mut_num);
pthread_cond_destroy(&cond);
exit(0);
}
例子3
5s循环打印abcd
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include <unistd.h>
#define THRNUM 4
static int num = 0;
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static void* thr_func(void *p) {
int n = (int)p; //线程号
char c = 'a' + n;
while (1) {
pthread_mutex_lock(&mut);
while (num != n) { //看看有没有轮到打印自己
pthread_cond_wait(&cond, &mut);//解锁等待
}
write(1, &c, 1);
num = (n + 1) % THRNUM; //变为下一个数
pthread_cond_broadcast(&cond);//唤醒所有(不用signal是不确定是不是下个线程会抢到)
pthread_mutex_unlock(&mut);
}
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
for (int i = 0; i < THRNUM; i++) {
err = pthread_create(tid + i, NULL, thr_func, (void*)i);
if (err) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
}
alarm(5); //5s后发出信号SIGALRM中断进程
for (int i = 0; i < THRNUM; i++) {
pthread_join(tid[i], NULL);//收尸
}
pthread_mutex_destroy(&mut);
pthread_cond_destroy(&cond);
exit(0);
}
11.信号量
互斥量+条件变量实现信号量机制(资源数为4)
mysem.h
#ifndef MYSEM_H__
#define MYSEM_H__
typedef void mysem_t;
mysem_t* mysem_init(int initval); //资源总量
int mysem_add(mysem_t *, int); //取走资源量 p操作
int mysem_sub(mysem_t*, int); //归还资源量 v操作
int mysem_destroy(mysem_t *);
#endif
mysem.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<pthread.h>
#include <unistd.h>
#include"mysem.h"
#include<string.h>
static pthread_mutex_t mut_job = PTHREAD_MUTEX_INITIALIZER; //这个互斥量保证job数组以独占形式存在
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_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;
}
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_destroy(mysem_t * ptr) {
struct mysem_st * me = ptr;
pthread_mutex_destroy(&me->mut);
pthread_cond_destroy(&me->cond);
free(me);
return 0;
}
main.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"mysem.h"
#include<pthread.h>
#define LEFT 30000000
#define RIGHT 30000200
#define THRNUM (RIGHT - LEFT + 1)
#define N 4 //同一时刻最多4个线程跑
static mysem_t* sem;
static void* thr_prime(void *i) {
int num = (int)i;
int mark = 1;
for (int j = 2; j < num / 2; j++) {
if (num % j == 0) {
mark = 0;
break;
}
}
if (mark)
printf("%d is a primer\n", num);
mysem_add(sem, 1); //归还资源量 v操作
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid[THRNUM];//线程数组
int mark, err;
sem = mysem_init(N);
if (sem == NULL) {
fprintf(stderr, "mysem_init() failed!\n");
exit(1);
}
for (int i = LEFT; i <= RIGHT; i++) { //201个线程每个处理一个数字
mysem_sub(sem, 1);取走资源量 p操作
err = pthread_create(tid + i - LEFT, NULL, thr_prime, (void*)i);
if (err) {
fprintf(stderr, "pthread_create(): %s\n", strerror(err));
exit(1);
}
}
for (int i = LEFT; i <= RIGHT; i++) {
pthread_join(tid[i - LEFT], NULL);//接收thr_prime返回的指针
}
mysem_destroy(sem);
exit(0);
}
12.线程属性
读写锁:读锁相当于共享锁,写锁相当于互斥锁
函数:
RETURN VALUE
On success, these functions return 0; on error, they return a nonzero error number.
pthread_attr_setstacksize:function sets the stack size attribute of the thread attributes object referred to by attr to the value specified in stacksize.
更多属性见man pthread_attr_init的see also
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string.h>
#include<pthread.h>
static void* func(void* p) {
while (1)
pause();
pthread_exit(NULL);
}
int main(int argc, char** argv) {
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024 * 1024);//1M大小
int i;
for (i = 0;; i++) {
int err = pthread_create(&tid, &attr, func, NULL);
if (err) {
fprintf(stderr, "pthraed_create():%s\n", strerror(err));
break;
}
}
printf("%d\n", i);
pthread_attr_destroy(&attr);
exit(0);
}
//输出5076
13.互斥量属性
函数:
pthread_mutexattr_init(pthread_mutexattr_t *attr)
pthread_mutexattr_destroy
pthread_mutexattr_getpshared
pthread_mutexattr_setpshared
clone
pthread_mutexattr_gettype
pthread_mutexattr_settype
14.条件变量属性
pthread_condattr_init
pthread_condattr_destroy
15.重入
很多标准io都可以实现多线程并发
3个线程分别打印‘aaa’,‘bbb’,‘ccc’,结果不会出现abcababcc这样的情况(内部已经实现互斥了)
不能实现线程安全的会在名字上体现
12.管道实例——池类写法
扩大池的容量
mypipe.h
#ifndef MYPIPE_H__
#define MYPIPE_H__
//#include <stdint.h>
#define PIPESIZE 1024 //管道大小
#define MYPIPE_READ 0x00000001UL //位图,1是读者
#define MYPIPE_WRITE 0x00000010UL //2是写者
typedef void mypipe_t;
mypipe_t* mypipi_init();
int mypipe_read(mypipe_t*, void* buf, size_t size); //真正读了多少数据
int mypipe_write(mypipe_t*, const void*, size_t); //真正写了多少数据
int mypipe_destroy(mypipe_t*);
int mypipe_register(mypipe_t*, int);
int mypipe_unregister(mypipe_t*, int);
#endif
mypipe.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"mypipe.h"
struct mypipe_st {
int head; //队头
int tail; //队尾
int datasize;//记录当前管道有多少有效字节数
char data[PIPESIZE];
int count_rd;
int count_wr;
pthread_mutex_t mut;
pthread_cond_t cond;
};
mypipe_t* mypipi_init() {
struct mypipe_st* me;
me = malloc(sizeof(*me));
if (me == NULL) {
return NULL;
}
me->head = 0;
me->tail = 0;
me->datasize = 0;
me->count_rd = 0;
me->count_wr = 0;
pthread_mutex_init(&me->mut, NULL);
pthread_cond_init(&me->cond, NULL);
}
static int mypipe_register(mypipe_t* ptr, int opmap) { //注册身份(读者or写者)
struct mypipe_st* me = ptr;
pthread_mutex_lock(&me->mut);
if (opmap & MYPIPE_READ) //是读者
me->count_rd++;
if (opmap & MYPIPE_WRITE) //是写着
me->count_wr++;
pthread_cond_broadcast(&me->cond);//叫醒其他等待注册自己身份的人,防止一直wait(下面代码)
while (me->count_rd <= 0 || me->count_wr <= 0)
pthread_cond_wait(&me->cond, &me->mut);
pthread_mutex_unlock(&me->mut);
return 0;
}
static int mypipe_unregister(mypipe_t* ptr, int opmap) {//注销身份
struct mypipe_st* me = ptr;
pthread_mutex_lock(&me->mut);
if (opmap & MYPIPE_READ) //是读者
me->count_rd--;
if (opmap & MYPIPE_WRITE) //是写着
me->count_wr--;
pthread_cond_broadcast(&me->cond);
pthread_mutex_unlock(&me->mut);
}
static int mypipe_readbyte_unlocked(struct mypipe_st* me, char* datap) {
if (me->datasize <= 0) //已经没有数据可读
return -1;
*datap = me->data[me->head];
me->head = (me->head + 1) % PIPESIZE;
me->datasize--;
return 0;
}
int mypipe_read(mypipe_t* ptr, void* buf, size_t count) { //真正读了多少数据
struct mypipe_st* me = ptr;
int i;
pthread_mutex_lock(&me->mut);
while (me->datasize <= 0 && me->count_wr > 0) { //管道没有内容并且有写者
//pthread_mutex_unlock(&mut_num); //松开 ,让别人尽快放进来
//sched_yield();
//pthread_mutex_lock(&mut_num);//加锁
pthread_cond_wait(&me->cond, &me->mut);
}
if (me->datasize <= 0 && me->count_wr <= 0) {
pthread_mutex_unlock(&me->mut);
return 0;
}
for (i = 0; i < count; i++) { //每次读一字节
if (mypipe_readbyte_unlocked(me, buf + i) == -1)//读取失败
break;
}
pthread_cond_broadcast(&me->cond);//通知所有write者,可以写
pthread_mutex_unlock(&me->mut);
return i;//返回真正读的数据
}
int mypipe_write(mypipe_t* ptr, const void* buf, size_t size) { //真正写了多少数据
}
int mypipe_destroy(mypipe_t* ptr) {
struct mypipe_st* me = ptr;
pthread_mutex_destroy(&me->mut);
pthread_cond_destroy(&me->cond);
free(ptr);
return 0;
}