Linux线程——线程同步

线程同步指的是当一个线程在对某个临界资源进行操作时,其他线程都不可以对这个资源进行操作,直到该线程完成操作,其他线程才能操作,也就是协同步调,让线程按预定的先后次序进行运行。线程同步的方法有四种:互斥锁、信号量、条件变量、读写锁。

1.互斥锁

头文件及函数声明:

#include <pthread.h>
/*
mutex是锁,
attr是锁的属性,一般用不上,传个NULL默认属性就可以
*/
int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr);

int pthread_mutex_lock(pthread_mutex_t *mutex);

int pthread_mutex_unlock(pthread_mutex_t *mutex);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

示例代码
以下代码在多线程并发中已经做过分析。我们这里直接进行修改。

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

pthread_mutex_t mutex;//定义锁
int g = 0;

void* pthread_fun(void* arg)
{
    for(int i = 0; i < 1000; i++)
    {
        pthread_mutex_lock(&mutex);//上锁
        g++;
        printf("g = %d\n",g);
        pthread_mutex_unlock(&mutex);//解锁
    }
    pthread_exit(NULL);
}

int main()
{
    
    pthread_mutex_init(&mutex, NULL);//初始化锁

    pthread_t id[5];
    for(int i = 0; i < 5; i++)
    {
        pthread_create(&id[i],NULL,pthread_fun,NULL);
    }

    for(int j = 0; j < 5; j++)
    {
        char* s = NULL;
        pthread_join(id[j],(void**)&s);
    }
    
    pthread_mutex_destroy(&mutex);//销毁锁
    exit(0);
}

运行结果最后输出都是5000,不会再出现低于5000的情况。

2 信号量

头文件及函数声明:

#include <semaphore.h>
/*
sem:信号对象。
pshared:指明信号量的类型。不为0时此信号量在进程间共享,为0时只能为当前进程的所有线程共享。
value:指定信号量值的大小。
*/
int sem_init(sem_t *sem, int pshared, unsigned int value);

int sem_wait(sem_t *sem);//原子操作,P操作,将信号值减1

int sem_post(sem_t *sem);//原子操作,V操作,将信号值加1

int sem_destroy(sem_t *sem);//销毁信号量

示例代码:函数线程完成将用户输入的数据存储到文件中

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

sem_t sem1;
sem_t sem2;
char buff[128] = {0};

void* pthread_fun(void* arg)
{
    int fd = open("sem.txt",O_WRONLY|O_CREAT,0664);
    assert(fd != -1);
    while(1)
    {
        sem_wait(&sem2);
        if(strncmp(buff,"end",3) == 0)
        {
            break;
        }
        write(fd,buff,strlen(buff));
        memset(buff,0,128);
        sem_post(&sem1);
    }
    sem_destroy(&sem1);
    sem_destroy(&sem2);
    pthread_exit(NULL);
}

int main()
{
    sem_init(&sem1,0,1);
    sem_init(&sem2,0,0);
    pthread_t id;
    int res = pthread_create(&id,NULL,pthread_fun,NULL);
    assert(res == 0);

    while(1)
    {
        printf("please input data:\n");

        sem_wait(&sem1);
        fgets(buff,128,stdin);
        buff[strlen(buff)-1] = '\0';
        sem_post(&sem2);

        if(strncmp(buff, "end", 3) == 0)
        {
            break;
        }
    }
    char* s = NULL;
    pthread_join(id,(void**)s);
    
    exit(0);
}

3.条件变量

条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。
头文件及函数声明:

#include <pthread.h>
/*
cond:
attr:
*/
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr);

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);

int pthread_cond_signal(pthread_cond_t *cond); //唤醒单个线程

int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒所有等待的线程

int pthread_cond_destroy(pthread_cond_t *cond);

示例代码:

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

pthread_mutex_t mutex;
pthread_cond_t cond;
void * fun1( void * arg)
{
	char* s = ( char*)arg;
	while( 1 )
	{
		//阻塞,被唤醒
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond,&mutex);
		pthread_mutex_unlock(&mutex);

		printf("fun1 read:%s\n",s);

		if (strncmp(s,"end",3) == 0 )
		{
			break;
		}
	}
}

void * fun2( void * arg)
{
	char* s = ( char*)arg;
	while( 1 )
	{
		//阻塞,被唤醒
		pthread_mutex_lock(&mutex);
		pthread_cond_wait(&cond,&mutex);
		pthread_mutex_unlock(&mutex);

		printf("fun2 read:%s\n",s);

		if ( strncmp(s,"end",3) == 0 )
		{
			break;
		}
	}
}

int main()
{
	pthread_t id[2];
	char buff[128] = {0};

	pthread_cond_init(&cond,NULL);
	pthread_mutex_init(&mutex,NULL);
	pthread_create(&id[0],NULL,fun1,( void*)buff);
	pthread_create(&id[1],NULL,fun2,( void*)buff);

	while( 1 )
	{
		fgets(buff,128,stdin);

		if ( strncmp(buff,"end",3) == 0 )
		{
			pthread_mutex_lock(&mutex);
			pthread_cond_broadcast(&cond);
			pthread_mutex_unlock(&mutex);

			break;
		}
		else
		{
			pthread_mutex_lock(&mutex);
			pthread_cond_signal(&cond);
			pthread_mutex_unlock(&mutex);
		}
	}

	pthread_join(id[0],NULL);
	pthread_join(id[1],NULL);
	exit(0);
}

4.读写锁

头文件及函数声明:

#include <pthread.h>
/*
rwlock:指向读写锁的指针
attr:读写锁属性,一般传入NULL,使用默认属性
每一个函数执行成功就返回0,否则就返回一个错误码
*/
int pthread_rwlock_init(pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);//都锁定

int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);//写锁定

int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);//解锁读写锁

int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//释放读写锁
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 线程同步是指多个线程之间协调工作,以避免出现竞态条件和死锁等问题。在Linux中,线程同步可以通过多种方式实现,例如互斥锁、条件变量、信号量等。其中,互斥锁是最常用的一种线程同步机制,它可以保证同一时间只有一个线程能够访问共享资源,从而避免了数据竞争的问题。另外,条件变量可以用于线程之间的通信和协调,而信号量则可以用于控制并发访问的数量。在实际应用中,需要根据具体的场景选择合适的线程同步机制,以确保程序的正确性和性能。 ### 回答2: 本文我们将继续介绍头linux线程同步的方法。 1. 互斥锁 互斥锁是最常用的一种线程同步机制。它通过提供一种机制,保证在同一时间只有一个线程能够访问共享资源。当一个线程获取了互斥锁,其他线程尝试获取该锁将会被阻塞,直到该线程释放锁。互斥锁的使用非常简单,头文件为pthread_mutex.h,相关函数有: - pthread_mutex_init() - pthread_mutex_lock() - pthread_mutex_trylock() - pthread_mutex_unlock() - pthread_mutex_destroy() 2. 条件变量 条件变量用于线程间的通讯,它典型的用法是一个线程等待某个条件变量的发生,而另一个线程则在条件变量满足的情况下通知等待的线程。条件变量需要和互斥锁配合使用,头文件为pthread_cond.h,相关函数有: - pthread_cond_init() - pthread_cond_wait() - pthread_cond_timedwait() - pthread_cond_broadcast() - pthread_cond_signal() - pthread_cond_destroy() 3. 读写锁 读写锁是一种特殊的锁,它允许多个读操作同时进行,但只允许一个写操作进行。在读多写少的情况下,使用读写锁可以提高并发性能。头文件为pthread_rwlock.h,相关函数有: - pthread_rwlock_init() - pthread_rwlock_rdlock() - pthread_rwlock_tryrdlock() - pthread_rwlock_wrlock() - pthread_rwlock_trywrlock() - pthread_rwlock_unlock() - pthread_rwlock_destroy() 4. 自旋锁 自旋锁是一种比较轻量级的锁,它不涉及进程上下文的切换,而是在内核级别上一直循环等待锁的释放。当锁的等待时间很短时,自旋锁的性能比较高。头文件为pthread_spinlock.h,相关函数有: - pthread_spin_init() - pthread_spin_lock() - pthread_spin_trylock() - pthread_spin_unlock() - pthread_spin_destroy() 总的来说,头linux提供了丰富的线程同步机制,开发者可以根据需求选择合适的方式。在实际应用中,要注意线程间的数据共享问题,以及线程死锁等问题。另外,根据linux系统的特点,线程同步会对系统性能产生一定的影响,需要对锁的粒度、优化等方面进行充分的考虑。 ### 回答3: 在Linux下实现线程同步有多种方法,其中包括使用信号量、互斥锁、条件变量等。在第一篇文章中,我们已经介绍了信号量的使用方法,本文将重点介绍互斥锁和条件变量。 互斥锁,也称为互斥量,是一种用于保护共享资源的同步机制。它可以使得在同一时间只有一个线程能够访问共享资源,从而避免多个线程同时访问而导致的竞态条件问题。在Linux中,使用pthread_mutex_t结构体可以创建和操作互斥锁。下面是一个简单的示例代码: ```c #include <pthread.h> pthread_mutex_t mutex; void *worker(void *arg) { // 获取互斥锁 pthread_mutex_lock(&mutex); // 临界区代码 // 释放互斥锁 pthread_mutex_unlock(&mutex); return NULL; } int main() { // 初始化互斥锁 pthread_mutex_init(&mutex, NULL); // 创建线程 pthread_t thread; pthread_create(&thread, NULL, worker, NULL); // join线程 pthread_join(thread, NULL); // 销毁互斥锁 pthread_mutex_destroy(&mutex); return 0; } ``` 在上面的示例中,我们使用了pthread_mutex_lock()和pthread_mutex_unlock()两个函数来分别获得和释放互斥锁。在执行临界区代码之前,我们必须先获取互斥锁,以确保在同一时间只有一个线程能够进入临界区。而在临界区代码执行完之后,我们需要释放互斥锁,以便其他线程也可以获取互斥锁并访问共享资源。 除了互斥锁以外,条件变量也是一种常用的线程同步机制。条件变量可以使得线程在满足某个条件之前一直等待,从而避免了忙等待的情况。在Linux中,使用pthread_cond_t结构体可以创建和操作条件变量。下面是一个简单的示例代码: ```c #include <pthread.h> pthread_mutex_t mutex; pthread_cond_t cond; int value = 0; void *worker(void *arg) { // 获取互斥锁 pthread_mutex_lock(&mutex); // 等待条件变量 while (value == 0) { pthread_cond_wait(&cond, &mutex); } // 临界区代码 // 释放互斥锁 pthread_mutex_unlock(&mutex); return NULL; } void *setter(void *arg) { // 获取互斥锁 pthread_mutex_lock(&mutex); // 设置共享变量 value = 1; // 发出条件变量信号 pthread_cond_signal(&cond); // 释放互斥锁 pthread_mutex_unlock(&mutex); return NULL; } int main() { // 初始化互斥锁和条件变量 pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond, NULL); // 创建线程 pthread_t thread1, thread2; pthread_create(&thread1, NULL, worker, NULL); pthread_create(&thread2, NULL, setter, NULL); // join线程 pthread_join(thread1, NULL); pthread_join(thread2, NULL); // 销毁互斥锁和条件变量 pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; } ``` 在上面的示例中,我们使用了pthread_cond_wait()和pthread_cond_signal()两个函数来分别等待和发出条件变量信号。当等待条件变量的线程被唤醒之后,它会重新获取互斥锁并进入临界区执行代码。而发出条件变量信号的线程可以在任意时间发出信号,让等待条件变量的线程重新开始执行。 总的来说,在Linux下实现线程同步有多种方法,我们需要根据具体情况选择不同的同步机制来保证共享资源的正确访问。同时,我们还需要注意在使用同步机制时避免死锁、竞态条件等问题的出现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孟小胖_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值