多线程
并发的三种实现手段
多线程,io多路复用,多进程
竞争
多线程的程序必须对任何可行的轨迹线都正确运行
死锁
就是等待一个永远不可能为真的值
当禁止区重叠的时候,就可能出现这种情况
可以调整枷锁的顺序进而:
关于二元信号量的不死锁条件
给定所有互斥操作的一个全序,如果每个线程都是以一种顺序获得互斥锁并以相反的顺序释放,那么这个程序就是无死锁的
线程安全函数
一个函数被称为线程安全的,当且仅当被多个并发线程反复调用时,他会一直产生正确的结果
典型的四类不安全的线程函数特点:
1.不保护共享变量的函数
2.保持跨越多个调用的状态的函数,如随机数生成器或者有局部静态变量
3.返回指向静态变量的指针的函数,如ctime,解决方法是加一个间接层拷贝数据,使之不返回指向静态变量的指针
4.调用线程不安全函数的函数
可重入性
没太明白意义
malloc,printf都是不可重入函数
可重入的函数必须满足以下三个条件:
(1)可以在执行的过程中可以被打断;
(2)被打断之后,在该函数一次调用执行完之前,可以再次被调用(或进入,reentered)。
(3)再次调用执行完之后,被打断的上次调用可以继续恢复执行,并正确执行。
获取线程返回值
pthread_join阻塞线程的同时获取返回值
pthread_exit = 单线程的exit,仅退出本线程,特别是pthread_exit主线程的时候,子线程不会被强制退出
pthread_kill(id,0)可以判断线程是否在运行
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
using namespace std;
void* returnVal(void *arg){
sleep(5);
return new int(100);
}
int main(){
pthread_t tid;
void *returnValue;
if (pthread_create(&tid,NULL,returnVal,NULL)){
cout << "pthread_thread filed" << endl;
return 0;
}
else{
auto check =
[=]() -> bool{
int tmp = pthread_kill(tid,0);
if (tmp == ESRCH){
return 0;
}
else if (tmp == EINVAL){
cout << "debug+ " << "kill failed" << endl;
exit(0);
}
else{
return 1;
}
};
cout << check() << endl;
pthread_join(tid,&returnValue);
cout << "result = " << *static_cast<int*>(returnValue) << endl;
cout << check() << endl;
return 0;
}
互斥的手段
信号量
在某些系统上,信号量是唯一可重入的互斥手段,消耗比较大
#include <stdio.h>
#include <semaphore.h>
#include <thread>
volatile int cnt = 0;
sem_t mutex;
void* thread(void *args){
int niters = *((long*)args);
for (int i = 0;i < niters;++i){
sem_wait(&mutex);
cnt++;
sem_post(&mutex);
}
return NULL;
}
int main(int argc,char **argv){
if (argc != 2){
printf("usage: %s <niters>\n",argv[0]);
exit(0);
}
else{
sem_init(&mutex,0,1);
int niters = atoi(argv[1]);
pthread_t tid1,tid2,tid3;
pthread_create(&tid1,NULL,thread,&niters);
pthread_create(&tid2,NULL,thread,&niters);
pthread_create(&tid3,NULL,thread,&niters);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
if (cnt != 2 * (niters)){
printf("BOOM! cnt = %d\n",cnt);
}
else{
printf("OK cnt = %d\n",cnt);
}
}
return 0;
}
互斥锁
简化版的信号量
spin lock
原子操作
2.6版本之后的linux不直接支持原子操作,要通过汇编实现
include <stdio.h>
#include <semaphore.h>
#include <thread>
#include <atomic>
using namespace std;
std::atomic<int> cnt;
void* thread1(void *args){
int niters = *((long*)args);
for (int i = 0;i < niters;++i){
++cnt;
}
return NULL;
}
int main(int argc,char **argv){
if (argc != 2){
printf("usage: %s <niters>\n",argv[0]);
exit(0);
}
else{
int niters = atoi(argv[1]);
pthread_t tid1,tid2,tid3;
pthread_create(&tid1,NULL,thread1,&niters);
pthread_create(&tid2,NULL,thread1,&niters);
pthread_create(&tid3,NULL,thread1,&niters);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
pthread_join(tid3,NULL);
if (cnt.load() != 3 * (niters)){
printf("BOOM! cnt = %d\n",cnt.load());
}
else{
printf("OK cnt = %d\n",cnt.load());
}
}
return 0;
}
条件变量
include 编译失败
g++ -odemo main.cpp -Wl,--no-as-needed -std=c++11 -lpthread
如果上述失败,试试这个
g++ -odemo -pthread test.c
-lpthread连接的仅仅是是libpthread, 但是-pthread连接的是libpthread和其他很多东西。
本文来自博客园,作者:XDU18清欢,转载请注明原文链接:https://www.cnblogs.com/XDU-mzb/p/16098021.html