sem_sempost函数(&sem[(no + THREAD_NUMBER - 1) % THREAD_NUMBER]);这句话怎么理解

信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  
sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  
函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  
函数sem_destroy(sem_t *sem)用来释放信号量sem。 
信号量用sem_init函数创建的,下面是它的说明:
#include&semaphore.h&
int sem_init (sem_t *sem, int pshared, unsigned int value);
这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。 (这个参数 受版本影响), pshared传递一个非零将会使函数调用失败。
这两个函数控制着信号量的值,它们的定义如下所示:
#include &semaphore.h&
int sem_wait(sem_t * sem);
int sem_post(sem_t * sem);
这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。
sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同 时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。
sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对 一个值为2的信号量调用sem_wait(),线程将会继续执行,介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就 会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加
一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
信号量这种“只用一个函数就能原子化地测试和设置”的能力下正是它的价值所在。 还有另外一个信号量函数sem_trywait,它是sem_wait的非阻塞搭档。
最后一个信号量函数是sem_destroy。这个函数的作用是在我们用完信号量对它进行清理。下面的定义:
#include&semaphore.h&
int sem_destroy (sem_t *sem);
这个函数也使用一个信号量指针做参数,归还自己战胜的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。
与其它的函数一样,这些函数在成功时都返回“0”。
#include &stdio.h&
#include &unistd.h&
#include &stdlib.h&
#include &string.h&
#include &pthread.h&
#include &semaphore.h&
sem_t bin_
void *thread_function1(void *arg)
{printf("thread_function1--------------sem_wait\n");sem_wait(&bin_sem);printf("sem_wait\n");while (1){}
void *thread_function2(void *arg)
{printf("thread_function2--------------sem_post\n");sem_post(&bin_sem);printf("sem_post\n");while (1){}
int main()
{pthread_t a_void *thread_res = sem_init(&bin_sem, 0, 0);if (res != 0){ perror("Semaphore initialization failed");} printf("sem_init\n");res = pthread_create(&a_thread, NULL, thread_function1, NULL);if (res != 0){ perror("Thread creation failure");}printf("thread_function1\n");sleep (5);printf("sleep\n");res = pthread_create(&a_thread, NULL, thread_function2, NULL);if (res != 0){ perror("Thread creation failure");}while (1){}
thread_function1
thread_function1--------------sem_wait
thread_function2--------------sem_post
sem_init,sem_post,sem_wait 信号量的用法解释
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__...
Linux信号量 sem_t简介
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。
函数sem_init()用来初始化一个信号量。它的原型为:int sem_init __P ((sem_t *...
对信号量sem的一些总结
1、首先来说说信号量和互斥锁的区别:
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,
别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里)。
多线程sem_init
用下面一组函数(系统调用)来实现。
int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_destroy(sem_...
linux sem信号量使用
Linux下关于信号量结构体表示为:sem_t
操作结构体的函数:
初始化函数: sem_init(sem_t * __sem,int __pshared,unsi...
sem_init函数用法
sem_init函数
sem_init函数是Posix信号量操作中的函数。sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信...
信号量sem_init,sem_wait,sem_post
本篇文章是信号量的简单入门,主要学习关于信号量四个函数的使用。
sem_init() 函数
编辑本段头文件
...
多线程使用信号量sem_init,sem_wait,sem_post
信号量的主要函数有:int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_wait(sem_t *sem);
int sem...
[root@init1 youshuang]# g++ main.cpp http_conn.cpp -o main出现如下报错:/tmp/cccJr4yJ.o:在函数‘sem::sem()’中:ma...
没有更多推荐了,信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));  
sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。  
函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。  
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。  
函数sem_destroy(sem_t *sem)用来释放信号量sem。 
信号量用sem_init函数创建的,下面是它的说明:
#include&semaphore.h&
int sem_init (sem_t *sem, int pshared, unsigned int value);
这个函数的作用是对由sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。pshared参数控制着信号量的类型。如果 pshared的值是0,就表示它是当前里程的局部信号量;否则,其它进程就能够共享这个信号量。我们现在只对不让进程共享的信号量感兴趣。 (这个参数 受版本影响), pshared传递一个非零将会使函数调用失败。
这两个函数控制着信号量的值,它们的定义如下所示:
#include &semaphore.h&
int sem_wait(sem_t * sem);
int sem_post(sem_t * sem);
这两个函数都要用一个由sem_init调用初始化的信号量对象的指针做参数。
sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同 时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。
sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对 一个值为2的信号量调用sem_wait(),线程将会继续执行,介信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就 会地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加
一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。
信号量这种“只用一个函数就能原子化地测试和设置”的能力下正是它的价值所在。 还有另外一个信号量函数sem_trywait,它是sem_wait的非阻塞搭档。
最后一个信号量函数是sem_destroy。这个函数的作用是在我们用完信号量对它进行清理。下面的定义:
#include&semaphore.h&
int sem_destroy (sem_t *sem);
这个函数也使用一个信号量指针做参数,归还自己战胜的一切资源。在清理信号量的时候如果还有线程在等待它,用户就会收到一个错误。
与其它的函数一样,这些函数在成功时都返回“0”。
#include &stdio.h&
#include &unistd.h&
#include &stdlib.h&
#include &string.h&
#include &pthread.h&
#include &semaphore.h&
sem_t bin_
void *thread_function1(void *arg)
{printf("thread_function1--------------sem_wait\n");sem_wait(&bin_sem);printf("sem_wait\n");while (1){}
void *thread_function2(void *arg)
{printf("thread_function2--------------sem_post\n");sem_post(&bin_sem);printf("sem_post\n");while (1){}
int main()
{pthread_t a_void *thread_res = sem_init(&bin_sem, 0, 0);if (res != 0){ perror("Semaphore initialization failed");} printf("sem_init\n");res = pthread_create(&a_thread, NULL, thread_function1, NULL);if (res != 0){ perror("Thread creation failure");}printf("thread_function1\n");sleep (5);printf("sleep\n");res = pthread_create(&a_thread, NULL, thread_function2, NULL);if (res != 0){ perror("Thread creation failure");}while (1){}
thread_function1
thread_function1--------------sem_wait
thread_function2--------------sem_post
sem_init函数用法
sem_init函数
sem_init函数是Posix信号量操作中的函数。sem_init() 初始化一个定位在 sem 的匿名信号量。value 参数指定信号量的初始值。 pshared 参数指明信...
sem_init()函数
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__...
信号量sem_init,sem_wait,sem_post
本篇文章是信号量的简单入门,主要学习关于信号量四个函数的使用。
sem_init() 函数
编辑本段头文件
...
多线程使用信号量sem_init,sem_wait,sem_post
信号量的主要函数有:int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_wait(sem_t *sem);
int sem...
有名信号量sem_open和内存信号量sem_init创建信号量的区别
有名信号量sem_open和内存信号量sem_init创建信号量的区别
分类: C/C++
sem_t *sem
sem_open(const char *name, int ofla...
信号量的用法和解释,sem_init,sem_wait
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__...
多线程sem_init
用下面一组函数(系统调用)来实现。
int sem_init(sem_t *sem,int pshared,unsigned int value);
int sem_destroy(sem_...
sem_init,sem_post,sem_wait 信号量的用法解释
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__...
* 生产者消费者模型
#define CONSUMER_COUNT 1
没有更多推荐了,信号量、同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已。但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆,关于用于进程间通信的信号量的详细介绍可以参阅我的另一篇博文:。相似地,线程同步是控制线程执行和访问临界区域的方法。
一、什么是信号量
线程的信号量与进程间通信中使用的信号量的概念是一样,它是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作。如果一个程序中有多个线程试图改变一个信号量的值,系统将保证所有的操作都将依次进行。
而只有0和1两种取值的信号量叫做二进制信号量,在这里将重点介绍。而信号量一般常用于保护一段代码,使其每次只被一个执行线程运行。我们可以使用二进制信号量来完成这个工作。
二、信号量的接口和使用
信号量的函数都以sem_开头,线程中使用的基本信号量函数有4个,它们都声明在头文件semaphore.h中。
1、sem_init函数
该函数用于创建信号量,其原型如下:
int sem_init(sem_t *sem, int pshared, unsigned int value);
该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示这个信号量是当前进程的局部信号量,否则信号量就可以在多个进程之间共享,value为sem的初始值。调用成功时返回0,失败返回-1.
2、sem_wait函数
该函数用于以原子操作的方式将信号量的值减1。原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。它的原型如下:
int sem_wait(sem_t *sem);
sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1.
3、sem_post函数
该函数用于以原子操作的方式将信号量的值加1。它的原型如下:
int sem_post(sem_t *sem);
与sem_wait一样,sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1.
4、sem_destroy函数
该函数用于对用完的信号量的清理。它的原型如下:
int sem_destroy(sem_t *sem);
成功时返回0,失败时返回-1.
三、使用信号量同步线程
下面以一个简单的多线程程序来说明如何使用信号量进行线程同步。在主线程中,我们创建子线程,并把数组msg作为参数传递给子线程,然后主线程等待直到有文本输入,然后调用sem_post来增加信号量的值,这样就会立刻使子线程从sem_wait的等待中返回并开始执行。线程函数在把字符串的小写字母变成大写并统计输入的字符数量之后,它再次调用sem_wait并再次被阻塞,直到主线程再次调用sem_post增加信号量的值。
#include &unistd.h&
#include &pthread.h&
#include &semaphore.h&
#include &stdlib.h&
#include &stdio.h&
#include &string.h&
//线程函数
void *thread_func(void *msg);
sem_//信号量
#define MSG_SIZE 512
int main()
int res = -1;
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);
//创建线程,并把msg作为线程函数的参数
res = pthread_create(&thread, NULL, thread_func, msg);
if(res != 0)
perror("pthread_create failed\n");
exit(EXIT_FAILURE);
//输入信息,以输入end结束,由于fgets会把回车(\n)也读入,所以判断时就变成了“end\n”
printf("Input some text. Enter 'end'to finish...\n");
while(strcmp("end\n", msg) != 0)
fgets(msg, MSG_SIZE, stdin);
//把信号量加1
sem_post(&sem);
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);
exit(EXIT_SUCCESS);
void* thread_func(void *msg)
//把信号量减1
sem_wait(&sem);
char *ptr =
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_wait(&sem);
//退出线程
pthread_exit(NULL);
运行结果如下:
从运行的结果来看,这个程序的确是同时在运行两个线程,一个控制输入,另一个控制处理统计和输出。
四、分析此信号量同步程序的缺陷
但是这个程序有一点点的小问题,就是这个程序依赖接收文本输入的时间足够长,这样子线程才有足够的时间在主线程还未准备好给它更多的单词去处理和统计之前处理和统计出工作区中字符的个数。所以当我们连续快速地给它两组不同的单词去统计时,子线程就没有足够的时间支执行,但是信号量已被增加不止一次,所以字符统计线程(子线程)就会反复处理和统计字符数目,并减少信号量的值,直到它再次变成0为止。
为了更加清楚地说明上面所说的情况,修改主线程的while循环中的代码,如下:
printf("Input some text. Enter 'end'to finish...\n");
while(strcmp("end\n", msg) != 0)
if(strncmp("TEST", msg, 4) == 0)
strcpy(msg, "copy_data\n");
sem_post(&sem);
fgets(msg, MSG_SIZE, stdin);
//把信号量加1
sem_post(&sem);
重新编译程序,此时运行结果如下:
当我们输入TEST时,主线程向子线程提供了两个输入,一个是来自键盘的输入,一个来自主线程复数据到msg中,然后从运行结果可以看出,运行出现了异常,没有处理和统计从键盘输入TEST的字符串而却对复制的数据作了两次处理。原因如上面所述。
五、解决此缺陷的方法
解决方法有两个,一个就是再增加一个信号量,让主线程等到子线程处理统计完成之后再继续执行;另一个方法就是使用互斥量。
下面给出用增加一个信号量的方法来解决该问题的代码,源文件名为semthread2.c,源代码如下:
#include &unistd.h&
#include &pthread.h&
#include &semaphore.h&
#include &stdlib.h&
#include &stdio.h&
#include &string.h&
//线程函数
void *thread_func(void *msg);
sem_//信号量
sem_t sem_//增加的信号量
#define MSG_SIZE 512
int main()
int res = -1;
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);
//输入信息,以输入end结束,由于fgets会把回车(\n)也读入,所以判断时就变成了“end\n”
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 =
//把信号量减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,并把它的初值赋为1,在主线程在使用sem_wait来等待子线程处理完全,由于它的初值为1,所以主线程第一次调用sem_wait总是立即返回,而第二次调用则需要等待子线程处理完成之后。而在子线程中,若处理完成就会马上使用sem_post来增加信号量的值,使主线程中的sem_wait马上返回并执行紧接下面的代码。从运行结果来看,运行终于正常了。注意,在线程函数中,信号量sem和sem_add使用sem_wait和sem_post函数的次序,它们的次序不能错乱,否则在输入end时,可能运行不正常,子线程不能正常退出,从而导致程序不能退出。
至于使用互斥量的方法,将会在下篇文章:中详细介绍。
Linux多线程(十二)线程和信号量
1.进程中每个线程都有自己的信号屏蔽字和信号未决字2.信号的处理方式是进程中所有线程共享的3.进程中的信号是递送到单个线程的4.定时器是进程资源,进程中所有的线程共享共同的定时器例1:
【C/C++多线程编程之七】pthread信号量
多线程编程之信号量
Pthread是 POSIX threads 的简称,是POSIX的线程标准。
互斥量用来处理一个共享资源的同步访问问题,当有多个共享资源时,就...
哲学家问题 pthread信号量实现
#define false 0
#define true 1
多线程编程(三)——线程同步——信号量
线程同步主要为了协调线程间工作,尤其是数据的使用,
第一个例子——生产者消费者:
#库存最多1,有库存消费者才消费,没则等待;没库存生产者才生产,没则等待。
#并没有用semA本身做...
C++ pthread 信号量及detach的使用
通过一个简单的例子,总结一下pthread中信号量的使用方式以及使用pthread_detach和使用pthread_join的区别。以备以后查阅。
涉及到的函数:
int pthread...
pthread互斥信号量使用总结
----一年前写的东西,重新抄录以防遗忘。
glibc提供的pthread互斥信号量可以用在进程内部,也可以用在进程间,可以在初始化时通过pthread_mutexattr_setpshared...
Linux 多线程同步(信号量)
sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续...
Linux多线程编程(三)-----生产者与消费者(条件变量,信号量)
Linux多线程编程(一):http://blog.csdn.net/llzk_/article/details/
Linux多线程编程(二):http://blog.csdn.ne...
信号量sem_t,互斥锁pthread_mutex_t的使用
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:  
extern int sem_init __P ((sem_t *__...
没有更多推荐了,详解Linux多线程使用信号量同步
&更新时间:日 15:21:35 & 作者:ljianhui
本篇文章主要是介绍了Linux多线程使用信号量同步,详细讲诉了信号量的接口和使用,有需要的朋友可以了解一下。
信号量、同步这些名词在进程间通信时就已经说过,在这里它们的意思是相同的,只不过是同步的对象不同而已。但是下面介绍的信号量的接口是用于线程的信号量,注意不要跟用于进程间通信的信号量混淆。
一、什么是信号量
线程的信号量与进程间通信中使用的信号量的概念是一样,它是一种特殊的变量,它可以被增加或减少,但对其的关键访问被保证是原子操作。如果一个程序中有多个线程试图改变一个信号量的值,系统将保证所有的操作都将依次进行。
而只有0和1两种取值的信号量叫做二进制信号量,在这里将重点介绍。而信号量一般常用于保护一段代码,使其每次只被一个执行线程运行。我们可以使用二进制信号量来完成这个工作。
二、信号量的接口和使用
信号量的函数都以sem_开头,线程中使用的基本信号量函数有4个,它们都声明在头文件semaphore.h中。
1、sem_init函数
该函数用于创建信号量,其原型如下:
int sem_init(sem_t *sem, int pshared, unsigned int value);
该函数初始化由sem指向的信号对象,设置它的共享选项,并给它一个初始的整数值。pshared控制信号量的类型,如果其值为0,就表示这个信号量是当前进程的局部信号量,否则信号量就可以在多个进程之间共享,value为sem的初始值。调用成功时返回0,失败返回-1.
2、sem_wait函数
该函数用于以原子操作的方式将信号量的值减1。原子操作就是,如果两个线程企图同时给一个信号量加1或减1,它们之间不会互相干扰。它的原型如下:
int sem_wait(sem_t *sem);
sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1.
3、sem_post函数
该函数用于以原子操作的方式将信号量的值加1。它的原型如下:
int sem_post(sem_t *sem);
与sem_wait一样,sem指向的对象是由sem_init调用初始化的信号量。调用成功时返回0,失败返回-1.
4、sem_destroy函数
该函数用于对用完的信号量的清理。它的原型如下:
int sem_destroy(sem_t *sem);
成功时返回0,失败时返回-1.
三、使用信号量同步线程
下面以一个简单的多线程程序来说明如何使用信号量进行线程同步。在主线程中,我们创建子线程,并把数组msg作为参数传递给子线程,然后主线程等待直到有文本输入,然后调用sem_post来增加信号量的值,这样就会立刻使子线程从sem_wait的等待中返回并开始执行。线程函数在把字符串的小写字母变成大写并统计输入的字符数量之后,它再次调用sem_wait并再次被阻塞,直到主线程再次调用sem_post增加信号量的值。
#include &unistd.h&
#include &pthread.h&
#include &semaphore.h&
#include &stdlib.h&
#include &stdio.h&
#include &string.h&
//线程函数
void *thread_func(void *msg);
sem_//信号量
#define MSG_SIZE 512
int main()
int res = -1;
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);
//创建线程,并把msg作为线程函数的参数
res = pthread_create(&thread, NULL, thread_func, msg);
if(res != 0)
perror("pthread_create failed\n");
exit(EXIT_FAILURE);
//输入信息,以输入end结束,由于fgets会把回车(\n)也读入,所以判断时就变成了“end\n”
printf("Input some text. Enter 'end'to finish...\n");
while(strcmp("end\n", msg) != 0)
fgets(msg, MSG_SIZE, stdin);
//把信号量加1
sem_post(&sem);
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);
exit(EXIT_SUCCESS);
void* thread_func(void *msg)
//把信号量减1
sem_wait(&sem);
char *ptr =
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_wait(&sem);
//退出线程
pthread_exit(NULL);
运行结果如下:
从运行的结果来看,这个程序的确是同时在运行两个线程,一个控制输入,另一个控制处理统计和输出。
四、分析此信号量同步程序的缺陷
但是这个程序有一点点的小问题,就是这个程序依赖接收文本输入的时间足够长,这样子线程才有足够的时间在主线程还未准备好给它更多的单词去处理和统计之前处理和统计出工作区中字符的个数。所以当我们连续快速地给它两组不同的单词去统计时,子线程就没有足够的时间支执行,但是信号量已被增加不止一次,所以字符统计线程(子线程)就会反复处理和统计字符数目,并减少信号量的值,直到它再次变成0为止。
为了更加清楚地说明上面所说的情况,修改主线程的while循环中的代码,如下:
printf("Input some text. Enter 'end'to finish...\n");
while(strcmp("end\n", msg) != 0)
if(strncmp("TEST", msg, 4) == 0)
strcpy(msg, "copy_data\n");
sem_post(&sem);
fgets(msg, MSG_SIZE, stdin);
//把信号量加1
sem_post(&sem);
重新编译程序,此时运行结果如下:
当我们输入TEST时,主线程向子线程提供了两个输入,一个是来自键盘的输入,一个来自主线程复数据到msg中,然后从运行结果可以看出,运行出现了异常,没有处理和统计从键盘输入TEST的字符串而却对复制的数据作了两次处理。原因如上面所述。
五、解决此缺陷的方法
解决方法有两个,一个就是再增加一个信号量,让主线程等到子线程处理统计完成之后再继续执行;另一个方法就是使用互斥量。
下面给出用增加一个信号量的方法来解决该问题的代码,源文件名为semthread2.c,源代码如下:
#include &unistd.h&
#include &pthread.h&
#include &semaphore.h&
#include &stdlib.h&
#include &stdio.h&
#include &string.h&
//线程函数
void *thread_func(void *msg);
sem_//信号量
sem_t sem_//增加的信号量
#define MSG_SIZE 512
int main()
int res = -1;
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);
//输入信息,以输入end结束,由于fgets会把回车(\n)也读入,所以判断时就变成了“end\n”
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 =
//把信号量减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,并把它的初值赋为1,在主线程在使用sem_wait来等待子线程处理完全,由于它的初值为1,所以主线程第一次调用sem_wait总是立即返回,而第二次调用则需要等待子线程处理完成之后。而在子线程中,若处理完成就会马上使用sem_post来增加信号量的值,使主线程中的sem_wait马上返回并执行紧接下面的代码。从运行结果来看,运行终于正常了。注意,在线程函数中,信号量sem和sem_add使用sem_wait和sem_post函数的次序,它们的次序不能错乱,否则在输入end时,可能运行不正常,子线程不能正常退出,从而导致程序不能退出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 semdilino 的文章

 

随机推荐