linu进程间通信,线程间同步

(以下纯属个人见解)
对于进程,多数的关注重点是在于 两个进程之间的通信,其实也存在同步的机制包含在"通信"里面,只是不同的进程拥有独立的地址空间,互不干涉,所以重点在于怎样让连个进程进行数据往来交流。

而线程,属于同一个进程创建的线程本来就是共享一些资源,所以讨论的侧重点也就不在于交流数据,而在于并发的时候怎么确保其和谐相处而不至于对一些公用的资源进行不合理的并发访问。这就是同步。

但是对于Linux来讲,其内部的线程本质上还是进程,只是已经对其进行了一些资源共享的操作,所以某些用于进程间 “同步”的手段,也一样适用于线程。比如信号量。

进程间通信
(有这一个文章讲得很是详细)
简单地列举下:
       1.0 管道(Pipe):及有名管道 (坦白来说,实际开发用的还真没见过)
       2.0 信号(Signal):类似于通知消息的机制。
       3.0 消息队列(Message): 这是个队列,比单纯的信号能存储更多的信号。
       4.0 共享内存:() 效率最高的一种通信方式。也是常用的一个
       5.0 信号量:(semaphore),主要是个同步手段,所以也用于线程之间的同步。典型的生产者消费者问题。
       6.0 套接口(Socket),本是为不同的主机之间的进程之间进行通信的,也可以用于本地机器的不同进程之间通信。


线程间同步
1.0 互斥锁
2.0 条件等待 :通常需要配合一个互斥锁一起使用。(使用场景后续)   pthread_cond_wait()函数一进入wait状态就会自动           release mutex,所以调用前先自行加锁。
3.0 信号量 :
     注意一个信号量和条件等待的细微区别:(个人见解)

     条件等待:pthread_cond_signal ()发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态。

      信号量,可以说是一个实际的物件,记住生产者消费者模式就可以很好地理解,但是条件等待,就不一样了,可以说条件等待是一个动态的 ”机遇“, 机遇稍纵即逝,pthread_cond_signal()产生一个条件,如果这个时候没有线程来把握住这个机会,pthread_cond_signal()返回,这个机会就没有了,条件就不成熟了。所以,你要先提前在这里“等待”。

比如这样的一个场景

void *ThreadBody(void * data)     
{       
      while(1)
      {
	pthread_mutex_lock(&p_sys->cmd_lock);
	do
	{
	  pthread_cond_wait(&cmd_wait, &cmd_lock);
          printf("hello world!\n");
	}while(0);
	pthread_mutex_unlock(&cmd_lock);
      }
		
}
	if(pthread_create( *, ThreadBody,NULL,NULL)
        {
               ....
        }	
		
        //usleep(1000);
        pthread_mutex_lock(&cmd_lock);
	do
	{
           pthread_cond_signal(&md_wait);
	}while(0);
	pthread_mutex_unlock(&cmd_lock);

本意是想创建一个线程,线程里面要条件等待,在创建完线程之后马上产生一个条件变量,然后线程就可以执行一次。而实际结果可能是,在pthread_cond_signal调用的时候,上面创建的线程创建虽然成功,但是还没被系统调度起来,等线程调度起来这个pthread_cond_signal已经返回了,线程没有等到这个条件。。。。加上上面的usleep确保线程优先被调度起来,可以。如果换成信号量,也不会出现这个问题。

概念如上,附上使用demo,方便查阅:

2.0 信号:

       一般老的接口是使用signal()函数,新的函数为 sigaction 区别:https://www.cnblogs.com/chllovegeyuting/archive/2012/09/10/2679178.html 一般使用sigaction()函数注册信号处理函数

信号量值,在Linux系统中 #kill -l 命令可以大概列出:

01 SIGHUP 挂起(hangup)
02 SIGINT 中断,当用户从键盘按^c键或^break键时
03 SIGQUIT 退出,当用户从键盘按quit键时
04 SIGILL 非法指令
05 SIGTRAP 跟踪陷阱(trace trap),启动进程,跟踪代码的执行
06 SIGIOT IOT指令
07 SIGEMT EMT指令
08 SIGFPE 浮点运算溢出
09 SIGKILL 杀死、终止进程 
10 SIGBUS 总线错误
11 SIGSEGV 段违例(segmentation  violation),进程试图去访问其虚地址空间以外的位置
12 SIGSYS 系统调用中参数错,如系统调用号非法
13 SIGPIPE 向某个非读管道中写入数据
14 SIGALRM 闹钟。当某进程希望在某时间后接收信号时发此信号
15 SIGTERM 软件终止(software  termination)
16 SIGUSR1 用户自定义信号1
17 SIGUSR2 用户自定义信号2
18 SIGCLD 某个子进程死
19 SIGPWR 电源故障

kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

 使用实例

#include<stdio.h>
#include <signal.h>
#include <sys/time.h> //for setitimer()

#include <unistd.h> //for sleep()

#include <sys/types.h> //for kill()
//#include <signal.h>


// #include <sys/types.h> //for getpid()
// #include <unistd.h>

int count  =100;

void fun_alarm(int sigNum)
{
	printf("get signal %d count %d[%d%s]\n",sigNum,count,__LINE__,__FUNCTION__);
}
int main()
{
	struct sigaction SigAction;
	SigAction.sa_handler = fun_alarm;
	SigAction.sa_flags = 0;
	sigemptyset(&SigAction.sa_mask);//clear 
	sigaction(SIGALRM,&SigAction,NULL);
	

	//case 1:  timer
	struct itimerval iTimer;
	iTimer.it_value.tv_sec = 3;//这个 int_value 是定时器的初始值
	iTimer.it_value.tv_usec = 0;
	iTimer.it_interval.tv_sec = 5;//定时器开始运行后,将从初始值往下减,当时间消耗完,用这个新值来重新设置,如果这个设为0,那么定时器只会运行一次
	iTimer.it_interval.tv_usec = 0;
	setitimer(ITIMER_REAL,&iTimer,NULL);//第三个参数,表示定时器多久之后开始运行,给NULL,立即开始 。定时器到时见产生一个 SIGALRM信号。

	while(count--)
	{
		sleep(1);
		if(95 == count)
		{//case 2: code self send signal
			printf("case 2: code kill send signal![%d%s]\n",__LINE__,__FUNCTION__);
			kill(getpid(),SIGALRM);
		}
	}

	//case 3: kill -14 pid //在外部 用kill -14 pid 给进程发送 信号 14

}

3.0 消息队列

4.0 共享内存

5.0 信号量

运行结果:
root@ubuntu:/mnt/hgfs/share/test# ./a.out
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
V: ++[33main]
P: --[13thread2]
^C
root@ubuntu:/mnt/hgfs/share/test# vi lock_test.c
root@ubuntu:/mnt/hgfs/share/test# cat lock_test.c 
代码:
#include<stdio.h>
#include <pthread.h>
#include <unistd.h>

#include <semaphore.h>

sem_t sem;
void *thread2(void *data)
{
	while(1)
	{
	 	sem_wait(&sem);
		printf("P: --[%d%s]\n",__LINE__,__FUNCTION__);
	}

}

pthread_t pid_pthread;

int main()
{
	sem_init(&sem,0,1);//第二个参数为 0 ,表示只在同一个进程下的线程间可用,非0表示不同的进程间可用
	if(pthread_create(&pid_pthread,NULL,thread2,NULL))
	{
		printf("thread create erro!\n");
		return -1;
	}
	pthread_detach(pid_pthread);

	while(1)
	{
		sleep(1);
		printf("V: ++[%d%s]\n",__LINE__,__FUNCTION__);
		sem_post(&sem);
		//sem_getvalue(sem_t *sem, int *sval);//可以获取信号量的值
	}

	sem_destroy(&sem);

}

6.0 互斥锁 :上述情景实例

       互斥锁的初始化有两种 方式:

        6.1 动态初始化:

                pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr)

                一般第二个参数,互斥锁属性 传NULL,表示默认属性

         6.2 静态初始化:

                 定义pthread_mutex_t变量的时候就给初始值,静态初始化

                pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

           6.3 互斥锁使用的时候,还有一种非阻塞方式,trylock,如果锁不可用,则不阻塞直接返回。

                     int pthread_mutex_trylock(pthread_mutex_t *mutex)

7.0 条件等待:上述情景实例

发布了96 篇原创文章 · 获赞 27 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/95170776