北京做手机网站的公司名称,数据可视化网站,北京建设银行网站,站点搜索线程同步 和 线程安全
线程同步
除了信号量和互斥锁#xff08;互斥锁和条件变量上次介绍过#xff09;#xff0c;还有两种方式同步
1.读写锁
当同时对一块内存读写时#xff0c;会出现下列问题#xff0c;故而引入读写锁 接口介绍#xff1a;
1.int pthread_rwloc…线程同步 和 线程安全
线程同步
除了信号量和互斥锁互斥锁和条件变量上次介绍过还有两种方式同步
1.读写锁
当同时对一块内存读写时会出现下列问题故而引入读写锁 接口介绍
1.int pthread_rwlock_init(pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr); 函数功能初始化读写锁 rwlock 传入定义的读写锁地址 attr : 读写锁的属性一般默认为 NULL 返回值如果成功函数应返回零 2.int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 函数功能加读锁其他线程无法写入 rwlock 传入定义的读写锁地址 3.int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 函数功能加写锁其他线程无法写入读取 rwlock 传入定义的读写锁地址 4.int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); 函数功能解锁允许读和写 rwlock 传入定义的读写锁地址 5.int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); 函数功能销毁读写锁 rwlock 传入定义的读写锁地址 测试代码
main.c
include unistd.h
#include stdio.h
#include stdlib.h
#include pthread.hpthread_rwlock_t rwlock;void *fun1(void *arg)
{for (int i 0; i 30; i){pthread_rwlock_rdlock(rwlock);printf(fun1 read start\n);sleep(1);printf(fun1 read end\n);pthread_rwlock_unlock(rwlock);sleep(1);}
}
void *fun2(void *arg)
{for (int i 0; i 10; i){pthread_rwlock_rdlock(rwlock);printf(fun2 read start\n);sleep(3);printf(fun2 read end\n);pthread_rwlock_unlock(rwlock);sleep(1);}
}
void *fun3(void *arg)
{for (int i 0; i 10; i){pthread_rwlock_wrlock(rwlock);printf(fun3 write start\n);sleep(3);printf(fun3 write end\n);pthread_rwlock_unlock(rwlock);sleep(1);}
}
int main()
{pthread_t id[3];pthread_rwlock_init(rwlock, NULL);pthread_create(id[0], NULL, fun1, NULL);pthread_create(id[0], NULL, fun2, NULL);pthread_create(id[0], NULL, fun3, NULL);for (int i 0; i 3; i){pthread_join(id[i], NULL);}pthread_rwlock_destroy(rwlock);exit(0);
}运行结果图 2.条件变量
条件变量提供了一种线程间的通知机制当某个共享数据达到某个值的时候唤醒等待 这个共享数据的线程。
接口介绍
1. int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr); 函数功能初始化条件变量 cond定义的条件变量的地址 attr条件变量的属性一般默认为 NULL 2. int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); 函数功能进入条件变量等待队列 cond定义的条件变量的地址 mutex定义的互斥锁的地址 3. int pthread_cond_signal(pthread_cond_t *cond); 函数功能 唤醒单个线程 cond定义的条件变量的地址 4. int pthread_cond_broadcast(pthread_cond_t *cond); 函数功能唤醒所有等待的线程 cond定义的条件变量的地址 5.int pthread_cond_destroy(pthread_cond_t *cond); 函数功能摧毁条件变量 cond定义的条件变量的地址 测试代码
#include unistd.h
#include stdio.h
#include stdlib.h
#include pthread.h
#include string.h
pthread_cond_t cond;
pthread_mutex_t mutex;void *fun1(void *arg)
{char *s (char *)arg;while (1){// 阻塞被唤醒pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);pthread_mutex_unlock(mutex);printf(fun1 read:%s\n, s);if (strncmp(s, end, 3) 0){break;}}
}
void *fun2(void *arg)
{char *s (char *)arg;while (1){// 阻塞被唤醒pthread_mutex_lock(mutex);pthread_cond_wait(cond, mutex);pthread_mutex_unlock(mutex);printf(fun2 read:%s\n, s);if (strncmp(s,end,3) 0){break;}}
}int main()
{pthread_cond_init(cond, NULL);pthread_mutex_init(mutex, NULL);pthread_t id[2];char buff[256]{0};pthread_create(id[0], NULL, fun1, (void*)buff);pthread_create(id[1], NULL, fun2, (void*)buff);while(1){printf(input: );fflush(stdout);fgets(buff,255,stdin);printf(\n);if(strncmp(buff,end,3) 0){pthread_cond_broadcast(cond);break;}else{pthread_cond_signal(cond);}sleep(1);}for(int i0;i2;i){pthread_join(id[i],NULL);}pthread_mutex_destroy(mutex);pthread_cond_destroy(cond);exit(0);
}运行结果图 线程安全
在多线程运行的时候不论线程的调度顺序怎样最终的结果都是一样的、正确的。那么就说这些线程是安全的。 要保证线程安全需要做到 1对线程同步保证同一时刻只有一个线程访问临界资源。 2在多线程中使用线程安全的函数可重入函数所谓线程安全的函数指的是如果一个函数能被多个线程同时调用且不发生竟态条件则我们程它是线程安全的。
下面展示使用不安全的线程函数举例
实现在两个线程中分别打印 char buff[] “a b c d e f g h i”; char buff[] “1 2 3 4 5 6 7 8 9”;两个数组
测试代码
#include stdio.h
#include stdlib.h
#include assert.h
#include unistd.h
#include string.h
#include pthread.hvoid *PthreadFun(void *arg)
{char buff[] a b c d e f g h i;char *p strtok(buff, );while (p ! NULL){printf(fun:: %c\n, *p);p strtok(NULL, );sleep(1);}
}int main()
{pthread_t id;int res pthread_create(id, NULL, PthreadFun, NULL);assert(res 0);char buff[] 1 2 3 4 5 6 7 8 9;char *p strtok(buff, );while (p ! NULL){printf(main:: %c\n, *p);p strtok(NULL, );sleep(1);}exit(0);
}运行结果 这是因为strtok()是线程不安全函数内部实现使用了全局变量或静态变量所以不能同时处理不同的字符串。
解决方法使用线程安全版的 strtok_r(); char *strtok_r(char *str, const char *delim, char **saveptr); str 数组 delim 分隔符 saveptr是指向char*变量的指针用来维护连续解析相同字符串的调用 代码如下
#include stdio.h
#include stdlib.h
#include assert.h
#include unistd.h
#include string.h
#include pthread.hvoid *PthreadFun(void *arg)
{char *q NULL;char buff[] a b c d e f g h i;char *p strtok_r(buff, ,q);while (p ! NULL){printf(fun:: %c\n, *p);p strtok_r(NULL, ,q);sleep(1);}
}int main()
{pthread_t id;int res pthread_create(id, NULL, PthreadFun, NULL);assert(res 0);char *q NULL;char buff[] 1 2 3 4 5 6 7 8 9;char *p strtok_r(buff, ,q);while (p ! NULL){printf(main:: %c\n, *p);p strtok_r(NULL, ,q);sleep(1);}exit(0);
}运行结果