首页 > 其他分享 >信号量/互斥锁/条件变量

信号量/互斥锁/条件变量

时间:2022-12-26 18:12:11浏览次数:40  
标签:变量 int void 信号量 互斥 mutex pthread 线程 sem

 1.信号量和互斥锁的使用场合

锁的特性就是保护临界资源的,一个线程A加锁,另一个线程B解锁,不合常理。A正在操作临界资源,B把A对临界资源的操作权限去除了……

线程间同步”的使用方法可以使用条件变量或者是信号量实现而不要使用mutex锁,mutex锁一般被用在保护线程间临界资源的情况下。

总结:sem_post(), sem_wait()实现线程同步。

pthread_mutex_lock,pthread_mutex_unlock实现防止临界资源竞态访问。

2.POSIX标准定义的信号量

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

功能:初始化信号量

返回值:创建成功返回0,失败返回-1

参数sem:指向信号量结构的一个指针

参数pshared:不为0时此信号量在进程间共享,为0时当前进程的所有线程共享

参数value:信号量的初始值

int sem_destroy(sem_t * sem)

功能:释放信号量自己占用的一切资源 (被注销的信号量sem要求:没有线程在等待该信号量了)

返回值:满足条件 成功返回0,否则返回-1且置errno为EBUSY

参数sem:指向信号量结构的一个指针

int sem_post(sem_t * sem)

功能:它的作用来增加信号量的值。给信号量加1。

返回值:操作成功返回0,失败则返回-1且置errno

参数sem:指向信号量结构的一个指针

int sem_wait(sem_t * sem)

功能:它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值(大于0)才开始做减法。(如果对一个值为0的信号量调用sem_wait(),这个函数就会等待,直到有其它线程增加了信号量这个值使它不再是0为止,再进行减1操作。)

返回值:操作成功返回0,失败则返回-1且置errno

参数sem:指向信号量结构的一个指针

int sem_trywait(sem_t * sem)

功能:sem_trywait()为sem_wait()的非阻塞版,不进行等待

返回值:如果信号量计数大于0,则信号量立即减1并返回0,否则立即返回-1,errno置为EAGAIN

参数sem:指向信号量结构的一个指针

int    sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)

功能:带超时的sem_wait

int sem_getvalue(sem_t * sem, int * sval)

功能: 读取sem中信号量计数

返回值: 操作成功返回0,失败则返回-1且置errno

参数sem:指向信号量结构的一个指针

参数sval:信号量计数值

在linux中定义位置usr/include/semaphore.h

测试:

#include <semaphore.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
  sem_t sem1;
  sem_t sem2;
  void *a_fn(void *arg)
  {
          sem_wait(&sem1);
          printf("thread a running\n");
          return (void *)0;
  }
  void *b_fn(void *arg)
  {
          sem_wait(&sem2);
          sem_post(&sem1);
          printf("thread b running\n");
          return (void *)0;
  }
  void *c_fn(void *arg)
  {
          sem_post(&sem2);
          printf("thread c running\n");
          return (void *)0;
  }

  int main(void)
  {
          pthread_t a, b ,c;
          sem_init(&sem1, 0, 0);
          sem_init(&sem2, 0, 0);
          pthread_create(&a, NULL, a_fn, (void *)0);
          pthread_create(&b, NULL, b_fn, (void *)0);
          pthread_create(&c, NULL, c_fn, (void *)0);
          pthread_join(a, NULL);
          pthread_join(b, NULL);
          pthread_join(c, NULL);
          sem_destroy(&sem1);
          sem_destroy(&sem2);
          return 0;
  }

3.POSIX标准定义的互斥锁

这里不做太多描述,主线程和子线程访问竞态资源变量g_buf,加mutex进行保护。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
static char g_buf[1000];
static sem_t g_sem;
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static void *my_thread_func (void *data)
{
        while (1)
        {
                //sleep(1);
                /* 等待通知 */
                //while (g_hasData == 0);
                sem_wait(&g_sem);
               /* 打印 */
              pthread_mutex_lock(&g_tMutex);
              printf("recv: %s\n", g_buf);
              pthread_mutex_unlock(&g_tMutex);
        }
        return NULL;
}
int main(int argc, char **argv)
{
        pthread_t tid;
        int ret;
        char buf[1000];
        sem_init(&g_sem, 0, 0);
        /* 1. 创建"接收线程" */
        ret = pthread_create(&tid, NULL, my_thread_func, NULL);
        if (ret)
        {
                printf("pthread_create err!\n");
                return -1;
        }
        /* 2. 主线程读取标准输入, 发给"接收线程" */
        while (1)
        {
                fgets(buf, 1000, stdin);
                pthread_mutex_lock(&g_tMutex);
                memcpy(g_buf, buf, 1000);
                pthread_mutex_unlock(&g_tMutex);
               /* 通知接收线程 */
               sem_post(&g_sem);
        }
        return 0;
}

相关函数:

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

int pthread_mutex_trylock(pthread_mutex_t *mutex);

4.POSIX标准定义的条件变量

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
static char g_buf[1000];
static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;
static void *my_thread_func (void *data)
{
        while (1)
        {
                //sleep(1);
                /* 等待通知 */
                //while (g_hasData == 0);
                pthread_mutex_lock(&g_tMutex);
                pthread_cond_wait(&g_tConVar, &g_tMutex);       
                /* 打印 */
                printf("recv: %s\n", g_buf);
                pthread_mutex_unlock(&g_tMutex);
        }
        return NULL;
}
int main(int argc, char **argv)
{
        pthread_t tid;
        int ret;
        char buf[1000];
        /* 1. 创建"接收线程" */
        ret = pthread_create(&tid, NULL, my_thread_func, NULL);
        if (ret)
        {
                printf("pthread_create err!\n");
                return -1;
        }
        /* 2. 主线程读取标准输入, 发给"接收线程" */
        while (1)
        {
                fgets(buf, 1000, stdin);
                pthread_mutex_lock(&g_tMutex);
                memcpy(g_buf, buf, 1000);
                pthread_cond_signal(&g_tConVar); /* 通知接收线程 */
                pthread_mutex_unlock(&g_tMutex);
        }
        return 0;
}

①创建和销毁条件变量

  // 初始化条件变量

  pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

  int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);    //cond_at tr 通常为 NULL

  int pthread_cond_destroy(pthread_cond_t *cond);

②等待条件变量

   int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);    //这需要结合互斥量一起使用

③ 通知条件变量

   int pthread_cond_signal(pthread_cond_t *cond);

5.线程的退出与回收

①线程主动退出

void pthread_exit(void *retval);

在退出时候可以传递一个 void*类 型的数据带给主线程,若选择不传出数据,可将参数填充为 NULL。

 ②线程被动退出

pthread_cancel(pthread_t thread);

成功:返回 0 该函数传入一个 tid 号,会强制退出该 tid 所指向的线程,若成功执行会返 回 0。

 ③线程资源回收(阻塞)

int pthread_join(pthread_t thread, void **retval);

该函数为线程回收函数,默认状态为阻塞状态,直到成功回收线程后才返回。第一个参数为要回收线程的 tid 号,第二个参数为线程回收后接受线程传 出的数据。

 ④线程资源回收(非阻塞方式)

int pthread_tryjoin_np(pthread_t thread, void **retval);

#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
void *fun1(void *arg)
{
        printf("Pthread:1 come!\n");
        while(1){
                sleep(1);
        }
}

void *fun2(void *arg)
{
        printf("Pthread:2 come!\n");
        pthread_cancel((pthread_t )(long)arg);
        pthread_exit(NULL);
}
int main()
{
        int ret,i,flag = 0;
        void *Tmp = NULL;
        pthread_t tid[2];
        ret = pthread_create(&tid[0],NULL,fun1,NULL);
        if(ret != 0){
                perror("pthread_create");
                return -1;
        }
        sleep(1);
        ret = pthread_create(&tid[1],NULL,fun2,(void *)tid[0]);
        if(ret != 0){
                perror("pthread_create");
                return -1;
        }
        while(1){
                for(i = 0;i <2;i++){
                        if(pthread_tryjoin_np(tid[i],NULL) == 0){
                                printf("Pthread : %d exit !\n",i+1);
                                flag++;        
                        }
                }
                if(flag >= 2) break;
        }
        return 0;
}

 

 

标签:变量,int,void,信号量,互斥,mutex,pthread,线程,sem
From: https://www.cnblogs.com/fuzidage/p/17006377.html

相关文章

  • python将字符串作为变量去赋值
    exec可将字符串作为变量去赋值,以下两个方式,value不能生效。原因不清楚,有大佬了解还请告知self.temp和value初始值都为-999以下代码执行结果为:1.0-999 ......
  • vite环境变量
    vite环境变量1、根目录创建.env.development、.env.production//.env.development开发环境地址NODE_ENV='development'VITE_BASE_URL='开发环境地址'//.env......
  • 信号量sem 的用法
    #include<semaphore.h> sem_tsem; sem_init(&sem,0,0);sem_post(&sem);sem_wait(&sem);sem_destroy(&sem); 信号量的数据类型为结构sem_t,它本质上是一个长......
  • linux中shell变量$#,$@,$0,$1,$2的含义解释
    linux中shell变量$#,$@,$0,$1,$2的含义解释:变量说明:$$Shell本身的PID(ProcessID)$!Shell最后运行的后台Process的PID$?最后运行的命令的结束代码(返回值)$-使用Set......
  • 线程之间的同步和互斥
                          ......
  • 信号量
               ......
  • TensorFlow中的Variable 变量
    简单运用这节课我们学习如何在Tensorflow中使用Variable.在Tensorflow中,定义了某字符串是变量,它才是变量,这一点是与Python所不同的。定义语法:state=tf.Varia......
  • Chapter.1 Extern | 我的变量怎么重复了? ——C++查漏补缺
    近期在学习C++,配合大牛书Primer看的效果还是很不错的。学到指针时又遇到了extern的使用,但自己回忆起来,好像在之前学过的内容里并没有对extern有非常深刻的印象。 于是结......
  • linux网络编程-线程——通过信号控制互斥锁
    1//由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,所以在使用pthread_create创建线程时,在编译中要加-lpthread参数2//gccpthread_sig_mutex.c-......
  • c语言register 变量
       【C语言】学习使用register定义变量的方法。_哔哩哔哩_bilibili 输出10......