linux线程通信

线程
进程是系统分配资源的基本单位
线程是系统调度的基本单位,共享进程的全部资源

一个进程可以有一个或者多个线程,线程一定对应一个进程

线程的属性之一:detach mode  默认是非分离状态,也就是需要主线程去回收资源的,用的是join。 

就绪---> 运行态  --->  阻塞 ---> 就绪

创建 : 进程fork 线程:pthread_create
回收资源: wait pthread_join 
结束 exit、_exit pthread_exit / pthread_cancel
注册退出处理: atexit pthread_cleanup_push & pthread_cleanup_pop
获得ID getpid pthread_self
fork得到子进程ID pthread_create也可以得到子线程ID
pthread_equal(pthread_t ,  pthread_t );

在线程中return (void *)0;  返回到调用线程
exit (0);  直接退出了进程
都能令线程正常终止

pthread_cancel(tid)只是调用者的愿望,tid对应的线程是否退出则需要看线程是否处于运行态
处于运行态的线程是不去响应这个cancel的
    针对非分离线程才有效,如果是线程已经分离,直接返回出错信息

pthread_equal(pthread_t ,  pthread_t );
pthread_t tid = pthread_self();
pthread_exit();

分离线程怎么创建
1: 从线程的属性上去设置分离或者非分离(默认)
属性:
pthread_attr_t attr
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid , 属性,线程函数入口,线程函数参数)

2: 从线程函数中,必须放在第一句  pthread_detach()
3:  一定要保证在线程调用 pthread_join(tid,NULL)之前, 
   就已经调用过pthread_detach(tid)或者是子线程中的pthread_detach(pthread_self())),这样才能生效

主线程不想或者不能阻塞在对该子线程的回收上时候, 希望子线程能够独立行事

pthread_cleanup_push & pthread_cleanup_pop
成对出现, 不能被分开, 
两个都是宏定义 , 暗含了{ 和}
如果代码在push和POP之间退出(不包含return)了, 那就会调用push中注册的函数

 调用函数的顺序和压栈、出栈顺序一致

pthread_cleanup_push   {
{
}
pthread_cleanup_pop    }

pthread_cleanup_pop(val) : val= 0:执行到pop语句的时候,不会调用push中注册的退出处理函数
= 1:执行到pop语句的时候,会调用push中注册的退出处理函数

线程间通信
: 
同步互斥机制:
信号量 sem   -----------------  同步机制 POSIX
互斥锁  mutex 
条件变量  pthread_cond           广播条件 等待条件成立
读写锁 rwlock

spin

信号量
sem_init
sem_wait  -- P 申请资源  sem_trywait   sem_timedwait
sem_post  -- v 释放资源

互斥锁

pthread_mutex_init
pthread_mutex_lock  / pthread_mutex_trylock
pthread_mutex_unlock
pthread_mutex_destroy

条件变量 (类似于信号)

pthread_cond_init
pthread_cond_wait()
偷解锁,在解锁状态下等待,得到条件变量后再次上锁 
pthread_cond_timedwait()
pthread_cond_signal()发送一次给等待该条件变量的一个进程
pthread_cond_broadcast() 发送给所有等待该条件变量的进程
pthread_cond_destroy()

注意:
临界资源(上锁和解锁之间的代码)应该尽可能简短,最好不要有延时之类的操作
一定在线程退出的时候,注意是否需要有释放锁的动作,
特别是在代码中途出现异常而退出的时候
--------------------------------------

信号量:sem
基本操作: init    sem_init (sem_t * , 0 , 1)
pshared == 1 表示在进程间使用该信号量,需要用到共享内存中的地址
  P 操作  sem_wait()  申请资源,申请到资源就信号量-1; 如果信号量为0,则会阻塞到信号量非零才返回;
sem_trywait 申请资源,申请到资源就信号量-1;如果信号量为0直接返回
sem_timedwait 申请资源,申请到资源就信号量-1;如果信号量为0就等一段时间,还等不到就直接返回

  V 操作  sem_post() 释放资源,信号量+1,而且唤醒睡眠中的等待该资源的线程或者进程

互斥锁:mutex 
 
pthread_mutex_init(pthread_mutex_t * , NULL)
restrict 表示只能通过该指针来修改该指针指向的内容

pthread_mutex_lock (pthread_mutex_t *)上锁 堵塞等待可上锁
pthread_mutex_trylock 如果已经上锁就直接返回。和锁的属性有关系, PTHREAD_MUTEX_RECURSIVE是会增加锁的个数

pthread_mutex_unlock (pthread_mutex_t *) 解锁

pthread_mutex_destroy (pthread_mutex_t *)  锁就变成不可用

实例:

实现Jack线程和Rose线程,并发送到消息队列,要求双方可以一直通信,直到互说88 结束线程

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/msg.h>
struct msg_st
{
	long int msg_type;// !!!!!!必须
	long msg_type_using; // 1:n  因为第一个参数msg_type是不能从data中获得的,所以多设置一个
	char buf[20];
};

int msgid = -1;

void *myThread1(void)
{
	
	struct msg_st data;
	long int msgtype = 1; // 0; // 2; //注意1  0


	while(1)
	{
		memset(data.buf,0,sizeof(data.buf));
		if(msgrcv(msgid, (void*)&data, (sizeof(struct msg_st) - sizeof(long int)), msgtype, 0) == -1)
		{
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		
		printf("myThread1 receive %s \n", data.buf);
		//结束
		if(strncmp(data.buf,"88",strlen("88"))==0)
		{
			printf("88\n");
			break;
		}
	
		data.msg_type  = 2; 
		//printf ("send to %ld : sum = %d \n", data.msg_type,data.sum);
		
		printf ("myThread1 send to a string:");
		fgets(data.buf,sizeof(data.buf),stdin);
		if(msgsnd(msgid, (void*)&data, (sizeof(struct msg_st) - sizeof(long int)), 0) == -1)
		{
			fprintf(stderr, "msgsnd failed\n");
			exit(EXIT_FAILURE);
		}
		
	
	}
		pthread_exit(NULL);
}

void *myThread2(void)
{
	int msgtype;
	struct msg_st data;
	while(1)
	{
		printf ("myThread2 send to a string:");
		fgets(data.buf,sizeof(data.buf),stdin);
		data.msg_type = 1;
		if(msgsnd(msgid, (void*)&data, (sizeof(struct msg_st) - sizeof(long int)), 0) == -1)
		{
			fprintf(stderr, "msgsnd failed\n");
			exit(EXIT_FAILURE);
		}
		
		memset(data.buf,0,sizeof(data.buf));
		msgtype = 2;
		if(msgrcv(msgid, (void*)&data, (sizeof(struct msg_st) - sizeof(long int)), msgtype, 0) == -1)
		{
			fprintf(stderr, "msgrcv failed with errno: %d\n", errno);
			exit(EXIT_FAILURE);
		}
		
		printf("myThread2 receive %s \n", data.buf);
		if(strncmp(data.buf,"88",strlen("88")) ==0 )
		{
			printf("88\n");
			break;
		}
		//data.msg_type  = data.msg_type_using +1; 
		
		
		
	}

	pthread_exit(NULL);
}

int main()
{
	int i=0, ret=0;
	pthread_t tid1,tid2;
	
		//建立消息队列
	msgid = msgget((key_t)1234, 0666 | IPC_CREAT);
	if(msgid == -1)
	{
		fprintf(stderr, "msgget failed with error: %d\n", errno);
		exit(EXIT_FAILURE);
	}
	printf("msgid = %d",msgid);

	printf("main creat thread1\n");
	ret = pthread_create(&tid1, NULL, (void*)myThread1, NULL);
	if (ret)
	{
		perror("Create pthread1 error:\n");
		return 1;
	}
	printf("main creat thread2\n");
	ret = pthread_create(&tid2, NULL,(void*) myThread2, NULL);
	if (ret)
	{
		perror("Create pthread2 error:");
		return 1; 
	}
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	while(1)
	{
		sleep(1);
	}
	return 0;
}

使用互斥锁通信

#include <stdio.h>
#include <pthread.h>
#include "stdlib.h"
#include "unistd.h"

pthread_mutex_t mutex;
pthread_cond_t cond;

void hander(void *arg)
{
	printf("exit in hander \n");
    free(arg);
    (void)pthread_mutex_unlock(&mutex);
}

void *thread1(void *arg)
{
     pthread_cleanup_push(hander, &mutex);
     while(1)
     {
         printf("thread1 is running\n");
         pthread_mutex_lock(&mutex); // 上锁1
		 printf("thread1 waiting ... \n");
         pthread_cond_wait(&cond,&mutex); // 偷解锁,在解锁状态下等待,得到条件变量后再次上锁 
         printf("thread1 applied the condition\n");
         pthread_mutex_unlock(&mutex);// 必须匹配LOCK 
     //    sleep(4);
     }
     pthread_cleanup_pop(0);
 }
 
void *thread2(void *arg)
{
     while(1)
     {
         printf("thread2 is running\n");
         pthread_mutex_lock(&mutex);// 上锁2
		 printf("thread2 waiting ... \n");
         pthread_cond_wait(&cond,&mutex);// 偷解锁,在解锁状态下等待,得到条件变量后再次上锁 
         printf("thread2 applied the condition\n");
         pthread_mutex_unlock(&mutex);
      //   sleep(1);
     }
}
int main()
{
     pthread_t thid1,thid2;
     printf("condition variable study!\n");
     pthread_mutex_init(&mutex,NULL);//互斥锁
     pthread_cond_init(&cond,NULL); // 条件变量
     pthread_create(&thid1,NULL,thread1,NULL);
     pthread_create(&thid2,NULL,thread2,NULL);
     sleep(1);
     do
     {
		 printf("signal cond \n");
         pthread_cond_broadcast(&cond);
		//pthread_cond_signal(&cond);
		sleep(2);
	}while(1);
     sleep(20);
     pthread_exit(0);
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值