线程2

线程同步

线程之间协同工作,用于多线程访问临界资源时,必须按照一定的先后顺序访问执行。
1.线程级的信号量
#include<semaphore.h>
sem_t sem;//类型
初始化
int sem_init(sem_t *sem,int shared,int val);
P操作
int sem_wait(sem_t *sem);
V操作
int sem_post(sem_t *sem);
删除
int sem_destroy(sem_*sem);
互斥锁:互斥量 加锁 解锁 一个临界资源进行控制
类型 phread_mutex_t
初始化:int pthread_mutex_init(pthread_mutex_t *mutex,pthread_mutexattr_t *attr);
加锁:int pthread_mutex_lock(pthread_mutex_t *mutex);
解锁:int pthread_mutex_unlock(pthread_mutex_t *mutex);
销毁:int pthread_mutex_destroy(pthread_mutex_t *mutex);

举例:将输入字母转成大写

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<semaphore.h>
#include<pthread.h>
pthread_mutex_t  mutex1;
pthread_mutex_t  mutex2;
char buff[128]={0};
void *fun(void *arg)
{
	while(1)
	{
		pthread_mutex_lock(&mutex1);
		if(strcmp(buff,"exit")==0)
		{
				break;
		}
		int i=0;
		for(;buff[i]!=0;i++)
		{
			if(buff[i]>='A'&&buff[i]<='Z')
			{
					printf("%c",buff[i]);
			}
			else
			{
					printf("%s",buff[i]-'a'+'A')
			}
		}
		pthread_mutex_unlock(&mutex2);
		printf("\n");
	}
	
}
void Destroy()
{
		printf("Destroy is  called\n");
		pthread_mutex_destroy(mutex1);
		pthread_mutex_destroy(mutex2);
}
int main()
{
	atexit(Destroy);
	pthread_t id;
	pthread_mutex_init(&mutex1,NULL);
	pthread_mutex_init(&mutex2,NULL);

	pthread_mutex_lock(&mutex2);
	printf("please input:");
	fgets(buff,128,stdin);
	buff[strlen(buff)-1]=0;
	
	pthread_mutex_unlock(&mutex1);
	
	if(strcmp(buff,"exit")==0)
	{
		break;
	}

}

分析:
首先如果在不加任何锁或者信号量的情况下,就会产生函数线程还未转换字母, 主线程已经进行到了下一次循环:

input:hello
input:HELLO

所以这种情况下,我们可以选择使用两把锁(信号量)来控制主线程与函数线程:
1.将锁2初始化之后就设为加锁状态。
2.对函数线程加锁1,在主线程中输入字符之后解锁1。
3.在主线程运行之前加锁2,在函数线程结束之后解锁2.

进程间同步的信号量是系统V信号量,线程间同步的信号量 POSIX,两个信号量不可交换使用。

线程安全

同一份程序,多次执行结果不同,执行结果有二义性。
安全原因:
1.线程是并发执行的或者是并行的。
2.操作的对象是同一个,线程之间数据(.data、.bss共享)
3.操作是非互斥的,在并行系统上。

解决:
1.使用不同的操作对象
2.线程同步。

char *strtok(char *str,char *sub);------>使用静态变量,线程不安全
char *strtok_r(char *str,char *sub,void **retptr);

1.多线程环境下创建子进程,由一个线程调用fork函数创建子进程,在子进程中,只有调动fork的线程会被启动,其他线程不会执行。
2.多线程环境下对锁进行加锁,然后创建进程,则子进程中对锁加锁可能会出现死锁。
子进程会复制父进程的锁

3.保证子进程赋值父进程的锁是解锁状态:

int pthread——atfork(void(*parent)(),void(*parent)(),void(*child)());

第一个参数:fork调用以后,真正复制进程之前执行,对父进程所有的锁进行加锁。
第二个参数:fork复制进程之后,在父进程空间中执行,对所有的锁解锁。
第三个参数:fork复制进程之后,在子进程空间中执行,对所有的锁解锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值