linux线程间通信之信号量

              这篇讲的是线程间的同步,进程间同步请移步:http://blog.csdn.net/shinichr/article/details/24306717

              线程间同步的信号量和进程很类似,但他们同步的对象不同了,接口也不一样了

             

              接口:

               1、sem_init函数: 创建信号量

                int sem_init(sem_t *sem, int pshared, unsigned int value); 

              该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示这个信号量是当前进程的局部信号量,否则信号量就可以在多个进程之间共享,value为sem的初始值。调用成功时返回0,失败返回-1.

               2、sem_wait函数 : 相当于p操作。该函数用于以原子操作(如果连个线程同时修改该值,是互不影响的)的方式将信号量的值减1

               int sem_wait(sem_t *sem);  

               sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1.

               3、sem_post函数      该函数用于以原子操作的方式将信号量的值加1。     

               int sem_post(sem_t *sem);      

               4、sem_destroy函数 信号量的清理               

               int sem_destroy(sem_t *sem);         都是成功时返回0,失败时返回-1.

       这里举个线程同步的例子,该例子实现一个线程收集用户输入,另一个将输入的字符转换成大写后输出

 

#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>


//线程函数
void *thread_func(void *msg);
sem_t sem;//信号量
sem_t sem_add;//增加的信号量


#define MSG_SIZE 512


int main()
{
	int res = -1;
	pthread_t thread;
	void *thread_result = NULL;
	char msg[MSG_SIZE];
	//初始化信号量,初始值为0
	res = sem_init(&sem, 0, 0);
	if(res == -1)
	{
		perror("semaphore intitialization failed\n");
		exit(EXIT_FAILURE);
	}
	//初始化信号量,初始值为1
	res = sem_init(&sem_add, 0, 1);
	if(res == -1)
	{
		perror("semaphore intitialization failed\n");
		exit(EXIT_FAILURE);
	}
	//创建线程,并把msg作为线程函数的参数
	res = pthread_create(&thread, NULL, thread_func, msg);
	if(res != 0)
	{
		perror("pthread_create failed\n");
		exit(EXIT_FAILURE);
	}
	printf("Input some text. Enter 'end'to finish...\n");
	
	sem_wait(&sem_add);
	while(strcmp("end\n", msg) != 0)
	{
		if(strncmp("TEST", msg, 4) == 0)
		{
			strcpy(msg, "copy_data\n");
			sem_post(&sem);
			//把sem_add的值减1,即等待子线程处理完成
			sem_wait(&sem_add);
		}
		fgets(msg, MSG_SIZE, stdin);
		//把信号量加1
		sem_post(&sem);
		//把sem_add的值减1,即等待子线程处理完成
		sem_wait(&sem_add);
	}


	printf("Waiting for thread to finish...\n");
	//等待子线程结束
	res = pthread_join(thread, &thread_result);
	if(res != 0)
	{
		perror("pthread_join failed\n");
		exit(EXIT_FAILURE);
	}
	printf("Thread joined\n");
	//清理信号量
	sem_destroy(&sem);
	sem_destroy(&sem_add);
	exit(EXIT_SUCCESS);
}


void* thread_func(void *msg)
{
	char *ptr = msg;
	//把信号量减1
	sem_wait(&sem);
	while(strcmp("end\n", msg) != 0)
	{
		int i = 0;
		for(; ptr[i] != '\0'; ++i)
		{
			if(ptr[i] >= 'a' && ptr[i] <= 'z')
			{
				ptr[i] -= 'a' - 'A';
			}
		}
		printf("You input %d characters\n", i-1);
		printf("To Uppercase: %s\n", ptr);
		//把信号量加1,表明子线程处理完成
		sem_post(&sem_add);
		//把信号量减1
		sem_wait(&sem);
	}
	sem_post(&sem_add);
	//退出线程
	pthread_exit(NULL);
}


 

这里为什么要用连个信号量呢?如果不加sem_add信号量,当输出线程很慢,比如在打印大写之前加个sleep,那输入端一直输入,输出端只知道最后一个字符串,并且打印多次(多次sem_post(&sem)),所以加个sem_add 是为了让输入端输入完了,等待输出端打印完.

比较差异:左边是没加sem_add 在输出端加了个sleep,右边是加了sem_add的

 

 

当然还可以用互斥量代替sem_add ,其实就是二进制信号量.

 

 

你可能感兴趣的:(linux,线程,同步,信号量)