linux多线程编程中使用信号量同步与互斥锁

一、什么是信号量

线程的信号量与进程间通信中使用的信号量是一样的,它是一个特殊的变量。可以被增加和减少,但对其的关键操作访问必须保证原子操作。如果一个程序中有多个线程试图改变一个信号量的值,系统将保证所有的操作都依次进行。

二、信号量的函数

信号量的函数都是以sem_开头,线程中使用的基本信号量函数有4个,在头文件semaphore.h中。

1、sem_init函数

该函数用于创建信号量,其原型如下:

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

(1) sem为要初始化的信号量指针。

(2)pshared表示此信号在进程间共享还是在线程间共享,0表示在线程间共享,1表示在进程间共享。

(3)value为信号量的初始值。

2、sem_post函数

 

该函数的原型如下:

       int sem_post(sem_t *sem);

 (1)该函数用于以原子操作的方式将信号量加1,并且会抛出信号,原本被阻塞的sem_wait将被打开。

(2)调用成功返回0,失败返回-1,并且设置error

 

3、sem_wait函数

该函数的原型如下:

int sem_wait(sem_t *sem);

 (1)该函数用于以原子操作的方式将信号量加-1,等待sem_post抛出信号来,否则一直阻塞。

(2)调用成功返回0,失败返回-1,并且设置error

4、sem_destory函数

该函数原型如下:

       int sem_destroy(sem_t *sem);

(1)该函数对用完的信号量清理

(2)调用成功返回0,失败返回-1,并且设置error

三、写一个简单的示例

用多线程实现输入一个非“end”的字符串,并且算出字符串的长度,输入“end”时则结束程序,要求用主线程实现输入并检查字符串是否为“end”,创建的新线程用来计算字符串的长度。

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

char buf[100] = {0};
sem_t sem;
int flag = 0;

void *func(void *argv)
{
    while(flag==0)
    {
        sem_wait(&sem);
        if(strcmp("end",buf))
        {
            printf("输入的字符串长度为%d\n",strlen(buf));
            memset(buf,0,sizeof(buf));
            printf("请输入一个非\"end\"的字符串\n");    
        }
    }
    pthread_exit(NULL);
}



int main(void)
{
    pthread_t th;
    
    /*创建一个新线程计算字符串的长度*/
    if(pthread_create(&th,NULL,func,NULL))
    {
        printf("创建新线程失败\n");
    }
    
    /*初始化线程间同步的信号量*/
    if(sem_init(&sem,0,0))
    {
        printf("初始化用于线程间同步的信号量失败\n");
    }

    printf("请输入一个非\"end\"的字符串\n");    

    while(scanf("%s",buf))
    {
       if(strcmp("end",buf)==0) 
       {
            sem_post(&sem);//唤醒正在等待的所有线程
            flag = 1;
            break;
       }
       sem_post(&sem);//唤醒正在等待的所有线程
    }


    /*回收子线程*/
    if(pthread_join(th,NULL))
    {
        printf("子线程回收失败\n");
    }
    else
    {
        printf("子线程回收成功\n");
    }
    
    /*回收sem信号量*/
    sem_destroy(&sem);
    return 0;
}

五、运行结果

root@ubuntu:/home/yong/c_c++/2019/9.9# 
root@ubuntu:/home/yong/c_c++/2019/9.9# ./a.out 
请输入一个非"end"的字符串
dwed
输入的字符串长度为4
请输入一个非"end"的字符串
fef
输入的字符串长度为3
请输入一个非"end"的字符串
efewf
输入的字符串长度为5
请输入一个非"end"的字符串
fwew
输入的字符串长度为4
请输入一个非"end"的字符串
end
子线程回收成功
root@ubuntu:/home/yong/c_c++/2019/9.9# 

六、什么是互斥锁 ?

互斥锁简单的可以认为是一种特殊的信号量,它的值只能是0和1,也就是上锁和解锁两种状态。

七、互斥锁函数

它们都在头文件pthread.h中,文件要加上#include<pthread.h>

1、pthread_mutex_init()

该函数的原型是:

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

(1)mutex指向要初始化的互斥锁对象

(2)attr位互斥属性,用NULL表示该属性缺省

(3)成功则返回0;失败则设置error

2、pthread_mutex_lock()

该函数原型是:

int pthread_mutex_lock(ptread_mutex_t *mutex);

 (1)mutex是互斥对象指针

 (2)成功返回0,失败则设置error

 (3)设置上锁,对于另外一个pthread_mutex_lock()函数则表示阻塞

3、pthread_mutex_unlock()

 (1)mutex是互斥对象指针

 (2)成功返回0,失败则设置error

 (3)设置解锁,解开pthread_mutex_lock()的锁

4、pthread_mutex_destroy()

 (1)mutex是互斥对象指针

 (2)成功返回0,失败则设置error

 (3)销毁一个互斥锁

八、用互斥锁来完成上面的需求

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

char buf[100] = {0};
int flag = 0;
pthread_mutex_t mutex;

void *func(void *argv)
{
    sleep(1);//延时一秒,因为先创建了子线程,子线程的中的循环要在主线程后面,所以需要延时
    while(flag==0)
    {
        pthread_mutex_lock(&mutex);//上锁,对一个上锁函数阻塞
        if(strcmp("end",buf))
        {
            printf("输入的字符串长度为%d\n",strlen(buf));
            memset(buf,0,sizeof(buf));
            printf("请输入一个非\"end\"的字符串\n");    
        }
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }
}



int main(void)
{
    pthread_t th;
    
    /*创建一个新线程计算字符串的长度*/
    if(pthread_create(&th,NULL,func,NULL))
    {
        printf("创建新线程失败\n");
    }
    
    /*初始化线程间互斥锁*/
    if(pthread_mutex_init(&mutex,NULL))
    {
        printf("初始化用于线程间同步的信号量失败\n");
    }

    printf("请输入一个非\"end\"的字符串\n");    

    while(1)
    {
        pthread_mutex_lock(&mutex);//上锁,对另一个函数进行阻塞
        scanf("%s",buf);
        if(strcmp("end",buf)==0) 
        { 
            flag = 1;
            pthread_mutex_unlock(&mutex);
            break;
        }
        pthread_mutex_unlock(&mutex);//解锁
        sleep(1);//让子线程先执行
    }


    /*回收子线程*/
    if(pthread_join(th,NULL))
    {
        printf("子线程回收失败\n");
    }
    else
    {
        printf("子线程回收成功\n");
    }
    
    /*销毁互斥锁*/
    if(pthread_mutex_destroy(&mutex))
    {
        printf("销毁互斥锁失败\n");
    }


    return 0;
}

运行结果

root@ubuntu:/home/yong/c_c++/2019/9.9# ./a.out 
请输入一个非"end"的字符串
wdew
输入的字符串长度为4
请输入一个非"end"的字符串
refregerg
输入的字符串长度为9
请输入一个非"end"的字符串
regerg
输入的字符串长度为6
请输入一个非"end"的字符串
reger
输入的字符串长度为5
请输入一个非"end"的字符串
ergerg
输入的字符串长度为6
请输入一个非"end"的字符串
end
子线程回收成功
root@ubuntu:/home/yong/c_c++/2019/9.9# 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值