linux线程同步教程,多线程同步
1.linux使用多线程同步的方法
1)互斥锁:当线程A锁定了互斥变量时,线程B再去锁定时就会被挂起,直到A解锁。
注意:当线程要不断的去轮询检查某个条件以判断是否可以操作需同步的数据时,可使用条件变量提高效率。
demo如下:
#include
#include
#include
pthread_mutex_t mutex;
void *print_msg(void *arg)
{
int i = 0;
pthread_mutex_lock(&mutex); //互斥锁加锁
for (i = 0; i < 20; i++)
{
printf(" i = %d\n", i);
usleep(200);
}
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_t id1, id2;
pthread_mutex_init(&mutex, NULL);
pthread_create(&id1, NULL, print_msg, NULL);
pthread_create(&id2, NULL, print_msg, NULL);
pthread_join(id1, NULL); //使主线程等待该线程结束后才结束,否则主线程很快结束,该线程没有机会执行
pthread_join(id2, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
2)信号量:实际是一个整数,只要信号量的value大于0,其他线程就可以sem_wait成功,成功后信号量的value减1。若value值不大于0,则sem_wait使得线程阻塞,直到sem_post释放后value值加1,但是sem_wait返回之前还是会将此value值减1。
demo如下:
#include
#include
#include
#include
#include
#include
void *thread_func(void* msg);
sem_t sem;
sem_t sem_add;
#define MSG_SIZE 512
int main()
{
int res = -1;
pthread_t thread;
void *thread_result = NULL;
char msg[MSG_SIZE];
res = sem_init(&sem, 0, 0);
if (res == -1)
{
printf("sem init failed\n");
exit(-1);
}
res = sem_init(&sem_add, 0, 1);
if (res == -1)
{
printf("sem_add init failed\n");
exit(-1);
}
res = pthread_create(&thread, NULL, thread_func, msg);
if (res != 0)
{
printf("pthread_create failed\n");
exit(-1);
}
printf("input some text. Enter 'end' to finish...\n");
sem_wait(&sem_add);
while(strcmp("end\n", msg) != 0)
{
if (strncmp(msg, "TEST", 4) == 0)
{
strcpy(msg, "copy_data\n");
sem_post(&sem);
sem_wait(&sem_add);
}
fgets(msg, MSG_SIZE, stdin);
sem_post(&sem); //sem信号量加1,让子线程开始执行
sem_wait(&sem_add); //sem_add信号量减1,等待子线程处理完成
}
printf("waiting for thread to finish...\n");
res = pthread_join(thread, &thread_result);
if (res != 0)
{
printf("pthread_join faild\n");
exit(-1);
}
printf("thread joined\n");
sem_destroy(&sem);
sem_destroy(&sem_add);
exit(0);
return 0;
}
void* thread_func(void* msg)
{
char *ptr = (char*)msg;
sem_wait(&sem);
while(strcmp("end\n", ptr) != 0)
{
int i = 0;
for (; ptr[i] != '\0'; ++i )
{
if (ptr[i] >= 'a' && ptr[i] <= 'z')
{
ptr[i] -= 'a' - 'A';
}
}
printf("you input %d characters\n", i - 1);
printf("to uppercase: %s\n", ptr);
sem_post(&sem_add);
sem_wait(&sem);
}
sem_post(&sem_add);
pthread_exit(NULL);
}
3)条件变量:经常和互斥锁一起使用,使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程会解开相应的互斥锁并等待条件发生变化,一旦其他的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此变量阻塞的线程,这些线程将重新锁定互斥锁并重新测试条件是否满足。
pthread_cont_init()
pthread_cont_destroy()
pthread_cont_wait() //线程解开mutex指向的锁并被条件变量阻塞
pthread_cont_timedwait() //多了时间参数,当时间过了以后,即使条件变量不满足,阻塞也被解除
pthread_cont_signal()/pthread_cont_broadcast //唤醒被条件变量阻塞的线程。
demo如下:
pthread1()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
if (sum >= 100)
{
pthread_cond_signal(&cond_sum_ready);//先发送一次
}
}
pthread2()
{
pthread_mutex_lock(lock_s);
while(sum < 100)
{
pthread_cond_wait(&cond_sum_ready, &lock_s);//会先执行pthread_MUTEX_UNLOCK进行解锁,然后休眠
}
sum = 0;
pthread_mutex_unlock(lock_s);
}
注意:最终哪个线程接收到信号,根据优先级来
4)读写锁:可以多个线程同时占用读模式的读写锁,但是只能一个线程占用写模式的读写锁。
当读写锁是写加锁状态时,在这个锁被解锁前,所有试图对这个锁加锁的线程都会被阻塞;
当读写锁是读加锁状态时,其他线程可以读模式得到访问权,但是以写模式对它进行加锁的线程都将被阻塞;
当读写锁是在读模式加锁状态时,如果有其他线程试图以写模式加锁,读写锁通常会阻塞随后的读模式锁请求,避免读模式锁长期占用,而写模式所长期阻塞;
读写锁适用于对数据读的次数比写的次数多的情况。
API接口:
初始化和销毁:
int pthread_rwlock_init();
int pthread rwlock_destroy();
读加锁、写加锁、解锁:
pthread_rwlock_rdlock();
pthread_rwlock_wrlock();
pthread_rwlock_unlock();
非阻塞获得读锁和写锁:
pthread_rwlock_tryrdlock();
pthread_rwlock_trywrlock();
demo如下
#include
#include
#include
#define Read_Num 2
pthread_rwlock_t lock;
class Data
{
public:
Data(int i, float f): I(i), F(f){}
int GetI()
{
return I;
}
float GetF()
{
return F;
}
private:
int I;
float F;
};
Data *pData = NULL;
void *read(void *arg)
{
int *id = (int*)arg;
while(true)
{
pthread_rwlock_rdlock(&lock);
printf(" reader %d is reading data\n", *id);
if (pData == NULL)
{
printf("data is NULL\n");
}
else
{
printf("data: I = %d, F = %f\n", pData->GetI(), pData->GetF());
}
pthread_rwlock_unlock(&lock);
}
pthread_exit(0);
}
void *write(void *arg)
{
while(true)
{
pthread_rwlock_wrlock(&lock); //写锁加锁后,解锁前,所有试图对该锁加锁的线程都会被堵塞
printf("writer is wiriting data:\n");
if (pData == NULL)
{
pData = new Data(2, 2.2);
printf("writer is writing data: %d, %f\n", pData->GetI(), pData->GetF());
}
else
{
delete pData;
pData = NULL;
printf("wirter free the data\n");
}
pthread_rwlock_unlock(&lock);
}
pthread_exit(0);
}
int main()
{
pthread_t reader[Read_Num];
pthread_t writer;
for (int i = 0; i < Read_Num; i++)
{
pthread_create(&reader[i], NULL, read, (void*)&i);
}
pthread_create(&writer, NULL, write, NULL);
while(1)
{
sleep(1);
}
return 0;
}
2.信号量和互斥锁之间的区别:
互斥锁用于互斥,对资源的访问是无序的,信号量用于同步,对资源的访问是有序的
互斥量的加锁和解锁必须由同一线程对应使用,而信号量可以由一个线程释放,另一个线程得到
3.什么情况下会产生死锁以及怎样避免死锁
比如线程A,对资源M加锁,去申请资源N;
线程B,对资源N加锁,去申请资源M;
此种情况下会产生死锁,要有效的避免死锁,可使用银行家算法:
线程A和B在使用资源的时候按照同一顺序,即加锁时按照同一顺序,这样就可以避免死锁。
linux线程同步教程,多线程同步相关推荐
- Linux 线程的创建与同步
Linux 线程的创建与同步 1.线程的定义 2.线程的创建和使用 3.理解线程的并发运行 3.线程同步 3.线程的实现 1.线程的定义 线程:进程内部的一条执行路径.是资源调度和执行的基本单位. 进 ...
- java 什么是线程同步,java多线程同步集合是什么?并发集合是什么?
java中关于集合的内容也是十分丰富的,而且相关的知识点也是十分多的.多线程集合所涵盖的范围是十分广阔的.今天就来为大家介绍一下,java多线程同步集合是什么以及并发集合是什么?一起来看看吧. 首先我 ...
- linux usleep 线程控制权_linux多线程同步—信号量
linux多线程编程-信号量 信号量机制 锁机制使用是有限制的,锁只有两种状态,即加锁和解锁,对于互斥的访问一个全局变量,这样的方式还可以对付,但是要是对于其他的临界资源,比如说多台打印机等,这种方式 ...
- java线程同步barrier_Java多线程同步工具类之CyclicBarrier
一.CyclicBarrier使用 CyclicBarrier从字面上可以直接理解为线程运行的屏障,它可以让一组线程执行到一个共同的屏障点时被阻塞,直到最后一个线程执行到指定位置,你设置的执行线程就会 ...
- linux线程池实现多线程并发,基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF...
基于Linux的多线程池并发Web服务器设计-电子设计工程.PDF 第 卷 第 期 电子设计工程 年 月 基于 的多线程池并发 服务器设计 陈 涛 任海兰 武汉邮电科学研究院 湖北 武汉 摘要 时至今 ...
- python 线程 的类库_python类库32[多线程同步Lock+RLock+Semaphore+Event]
多线程基础:python类库32[多线程同步] 一 多线程同步 由于CPython的python解释器在单线程模式下执行,所以导致python的多线程在很多的时候并不能很好地发挥多核cpu的资源.大部 ...
- WinAPI多线程同步
WinAPI多线程同步 WINAPI多线程同步主要有5种方式:全局变量.事件.临界区.互斥量.信号量. 代码是多线程编程的入门代码,为了让自己熟悉基础操作,保留笔记,方便日后查询,下面分别展示各方法示 ...
- Linux 线程间通信方式、进程通信方式
Linux线程间通信几种主要的手段 1. 管道: 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有 ...
- linux进程同步问题,关于LINUX下进程和线程对文件的同步问题,请高手来看看!!!...
不知道大家有没有碰到过这样的问题,即在LINUX下的程序有时候会碰到多个进程访问同一个文件, 以及一个进程的不同线程对一个文件的同步问题,我尝试用了系统提供的fcntl函数来给文件加锁, 但是这只是一 ...
最新文章
- C++实现有哨兵的双向循环链表
- Servlet中的监听器
- 熊猫数据集_用熊猫掌握数据聚合
- java innodb存储引擎_InnoDB存储引擎简介
- python教程2017百度云_python下载ICCV2017全套paper
- 马斯克又一语双关 引用猫王金曲威胁直接向推特股东发要约收购?
- Pytorch:手动求导和autograd的计算对比
- mysql交叉组合查询,MySQL数据透视/交叉表查询
- jquery知识点总结(转载)
- html常用布局标签的合理搭配
- 利用SQL求中位数(已修复BUG)
- java contains 大小写_使用.contains方法忽略大小写的选项?
- Wlan学习备忘(上)
- 融资2500万美元,#Spatial从协作办公进化到元宇宙产品,#NFT创作生态
- android+像素转换工具,MCPE像素画生成器
- Java按钮监听器ActionListener 事件监听教程.
- proftpd的SSH_DISCONNECT (Read TImed out,Key exchange failed.错误解决
- 不是吧阿sir,你不会还不知道Github可以当做Maven仓库吧
- IntelliJ IDEA:安装/搭建/配置/插件
- uniapp 压缩照片
热门文章
- python连接mongo_使用简单的Python连接访问MongoDB
- 电脑卡顿不流畅是什么原因_什么造成游戏直播画画卡顿、延迟?这三个原因了解一下...
- linux系统的安全机制有哪些内容,系统安全机制
- [转载] Java静态绑定与动态绑定
- inputstream示例_Java InputStream close()方法与示例
- php知识点汇总与解答_PHP操作员能力倾向问题与解答
- css div滚动_如何使用CSS创建可垂直滚动的div?
- python调用菜单响应事件_Python处理菜单消息操作示例【基于win32ui模块】
- echaer 地图_ECharts地图系列
- java setsize_Java Vector setSize()方法与示例