1、线程安全:
多线程程序无论调度顺序如何,都能保证程序 的正确性,就说该程序处于线程安全的状态
1)、同步
2)、线程安全函数//有的函数不适合多线程使用,是函数自身的原因。
2、线程安全函数
1)非线程安全函数
分割函数//不是线程安全函数
strtok(buff," 分隔符")//非线程安全函数,
如果有静态变量或者全局变量,对于多线程来说,访问是不安全的。属于非线程安全函数
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *fun(void*arg)
{
char buff[128]={a b c d };
char*s=strtok(buff," ");
while(s!=NULL)
{
printf("%s\n",s);
s=strtok(NULL," ");
}
}
int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
char arr[128]={1 2 3 4 5};
char*p=strtok(arr," ");
whlie(p!=NULL)
{
printf("%s\n",p);
p=strtok(NULL," ");
}
pthread_join(id,NULL);
exit(0);
}
2)线程安全函数
线程安全分割函数
strtok_r(buff," ",&ptr);
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *fun(void*arg)
{
char buff[128]={a b c d };
char*ptr=NULL;
char*s=strtok_r(buff," ",&ptr);
while(s!=NULL)
{
printf("%s\n",s);
s=strtok_r(NULL," ",&ptr);
}
}
int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
char arr[128]={1 2 3 4 5};
char*ptr=NULL;
char*p=strtok_r(arr," ",&ptr);
whlie(p!=NULL)
{
printf("%s\n",p);
p=strtok_r(NULL," ",&ptr);
}
pthread_join(id,NULL);
exit(0);
}
3、多线程程序执行fork()
1)多线程程序:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*fun(void *arg)
{
for(int i=0;i<5;i++)
{
printf("fun(%d) run\n",getpid());
sleep(1);
}
}
int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
for(int i=0;i<5;i++)
{
printf("main(%d) run\n",getpid());
sleep(1);
}
pthread_join(id,NULL);
exit(0);
}
2)多线程 复制子进程
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void*fun(void *arg)
{
for(int i=0;i<5;i++)
{
printf("fun(%d) run\n",getpid());
sleep(1);
}
}
int main()
{
pthread_t id;
pthread_create(&id,NULL,fun,NULL);
fork ();
for(int i=0;i<5;i++)
{
printf("main(%d) run\n",getpid());
sleep(1);
}
pthread_join(id,NULL);
exit(0);
}
多线程 fork()后只会执行一条路径,他在哪一个路径中他就会执行那一条路径,但是其他路径的资源他是有的,只不过不执行了
4、创建一个锁,fork()之后看子进程的情况
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/wait.h>
pthread_mutex_t mutex;
void*fun(void *arg)
{
pthread_mutex_lock(&mutex);
sleep(5);//线程睡眠5秒
pthread_mutex_unlock(&mutex);
printf(" fun free\n");
}
int main()
{
pthread_t id;
pthread_mutex_init(&mutex,NULL);
pthread_create(&id,NULL,fun,NULL);
sleep(1);//主线程睡眠一秒
pid_t pid=fork();//复制的时候,父进程处于加锁状态
if(pid==0)
{
printf("child lock\n");
pthread_mutex_lock(&mutex);
printf("child success");
pthread_mutex_unlock(&mutex);
}
else
{
wait(NULL);
}
printf("main over");
pthread_mutex_destroy(&mutex);
pthread_join(id,NULL);
exit(0);
}
子进程没有加锁成功
1)加锁失败原因:
父进程和子进程的锁各自是各自的,是两把锁。
锁的状态,会在复制进程时,被复制,在复制时,父进程的锁是加锁,复制后,子进程的锁也是加锁,同样不加锁也是。是不固定的,子进程中锁的状态不清晰。
2)解决办法:pthread_atfork()
会在没有人用锁的情况下对进程进行复制,确保子进程所得状态时清晰的。
void parent_fun(void)
{
pthread_mutex_lock(&mutex);
}
void child_fun(void)
{
pthread_mutex_unlock(&mutex);
}
int main()
{
pthread_atfork(parent_fun,child_fun.child_fun);
//写入主函数,会在复制子程序之前执行
}
弊端是会延迟fork的复制
5、进程同步——条件变量
进程同步的方法:信号量 互斥锁 读写锁 条件变量
线程先将自己堵塞在条件变量等待队列上,等条件满足之后,唤醒一个或者全部
//条件满足就工作,条件不满足就休息//条件由用户决定。
在唤醒的时候,不希望有别的进出这个给队列,所以在唤醒时加锁
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
char buff[128]={0};
void *funa(void*arg)
{
while(1)
{
pthread_mutex_lock(&mutex);//唤醒前加锁
pthread_cond_wait(&cond,&mutex);
pthread_mutex_unlock(&mutex);
if(strncmp(buff,"end",3)==0)
{
printf("funa:%s",buff);
}
}
}
void*funb(void*arg)
{
{
while (1)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond,&mutex);
pthread_mutex_unlock(&mutex);
}
if(strncmp(buff,"end",3)==0)
{
printf("funb:%s",buff);
}
}
}
int main()
{
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
pthread_t id1,id2;
pthread_create(&id1,NULL,funa,NULL);
pthread_create(&id2,NULL,funb,NULL);
while(1)
{
char tmp[128]={0};
fgets(tmp,128,stdin);
strcpy(buff,tmp);
if(strncmp(tmp,"end",3)==0)
{
pthread_cond_broadcast(&cond);//唤醒全部进程
break;
}
else
{
pthread_cond_signal(&cond);//唤醒单个进程(轮流唤醒)
}
}
pthread_join(id1,NULL);
pthread_join(id2,NULL);
}