Linux高级编程7 - 线程控制

        要引入线程控制这个概念是由于在多线程中存在资源竞争的问题,导致结果与想的不一样。

比如这个程序,想实现的A加到10000去。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int A = 0 ;
void * th(void* arg)
{
    
    int i = 5000;
    while(i--)
    {
        int tmp = A;
        printf("A is %d\n",tmp+1);
        A = tmp+1;
    }
    return NULL;
}
int main(int argc, char *argv[])
{
    pthread_t tid1,tid2;
    pthread_create(&tid1,NULL,th,NULL);
    pthread_create(&tid2,NULL,th,NULL);

    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    return 0;
}

运行结果却是这样的

所以要引入线程控制的互斥与同步量;

一、线程控制:

        互斥锁:在多线程中对临界资源的排他性访问。特点:谁上锁谁解锁

       线程控制(互斥)的执行步骤:定义互斥锁、初始化锁、加锁、解锁、销毁。

        1、定义互斥锁:pthread_mutex_t   mutex;

        2、初始化锁:初始化互斥锁,使其处于可用状态。

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

        参数:

                mutex:要初始化的互斥锁。

                attr:互斥锁的属性设置,通常传递 NULL 使用默认属性。

        返回值:0成功,非零失败

        3、加锁:锁定互斥锁,以保护共享资源。其他线程在该锁被释放之前不能访问被保护的代码段。

int pthread_mutex_lock(pthread_mutex_t *mutex);

        返回值:成功返回 0;失败返回非零值。

        注意:如果互斥锁已经被其他线程加锁,调用 pthread_mutex_lock 的线程将被阻塞,直到锁被释放。避免在持有锁的线程中调用可能导致死锁的函数。

        4、解锁:解锁互斥锁,使其他线程可以获取该锁。

int pthread_mutex_unlock(pthread_mutex_t *mutex);

        返回值:成功返回 0;失败返回非零值。

        注意:每次加锁操作后必须对应一个解锁操作,以防止死锁和资源泄漏。

        5、销毁:销毁互斥锁,释放相关的系统资源。

int pthread_mutex_destroy(pthread_mutex_t *mutex);

        返回值:成功返回 0;失败返回非零值。

        注意:在销毁互斥锁之前,确保所有线程都已经释放了对该锁的持有,并且该互斥锁不再被使用。

         6、trylock():尝试获取锁而不阻塞。如果锁已经被其他线程持有,则立即返回而不阻塞当前线程。

int pthread_mutex_trylock(pthread_mutex_t *mutex);

        返回值:成功返回 0,表示成功获取锁。失败返回非零值

        用多线程程序设计一个火车票售票系统, 要求至少有两个售票窗口,每个售票窗口不能重复买票,将100张车票均匀的从两个窗口卖出即可。


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int WIN =3;
pthread_mutex_t mutex;
void* th(void* arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        if(WIN>0)
        {
            WIN--;
            pthread_mutex_unlock(&mutex);
            printf("get win\n");
            sleep(rand()%5);
            printf("relese win\n");
            pthread_mutex_lock(&mutex);
            WIN++;
            pthread_mutex_unlock(&mutex);
            break;
        }
        else 
        {
            pthread_mutex_unlock(&mutex);

        }
    }
    return NULL;
}
int main(int argc, char *argv[])
{
    int i = 0 ;
    pthread_mutex_init(&mutex,NULL);
    pthread_t tid[10]={0};
    for(i=0;i<10;i++)
    {
        pthread_create(&tid[i],NULL,th,NULL);
    }
    for(i=0;i<10;i++)
    {
        pthread_join(tid[i],NULL);
    }
    pthread_mutex_destroy(&mutex);
    return 0;
}

产生死锁的原因主要是:
        (1) 因为系统资源不足。
        (2) 进程运行推进的顺序不合适。
        (3) 资源分配不当等。
         如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则
就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。
产生死锁的四个必要条件:
        (1) 互斥条件:一个资源每次只能被一个进程使用。
        (2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
        (3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
        (4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

2、信号量:有一定先后顺序的对资源的排他性访问。特点:上锁与解锁执行者不一样。

        信号量的步骤:信号量的定义、信号量的初始化、信号量的PV操作、信号量的销毁

        1.信号量定义:sem_t sem;

        2. 信号量的初始化:初始化一个信号量。

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

        参数:

                sem:要初始化的信号量。

                pshared:如果为 0,信号量在线程间共享;如果不为 0,信号量在进程间共享。

                value:信号量的初始值。通常用来设置信号量的计数值,例如 0 表示不可用,1 表示可用。

        返回值:成功返回 0;失败返回 -1。

        注意:信号量的初始值应根据具体应用场景设置。例如,如果你希望一个信号量用于控制对某个共享资源的互斥访问,可以将初始值设为 1,表示资源是可用的。

        3. 信号量的 PV 操作

        信号量的 PV 操作包括 P(Proberen,申请资源)和 V(Verhogen,释放资源)。在 POSIX 信号量中,P 操作对应 sem_wait,V 操作对应 sem_post。

int sem_wait(sem_t *sem);

        功能:申请信号量资源。如果信号量的值大于 0,则资源被分配,信号量值减 1;如果信号量值为 0,线程会被阻塞,直到信号量有可用资源。

int sem_post(sem_t *sem);

        功能:释放信号量资源,将信号量的值增加 1。如果有线程因信号量值为 0 而被阻塞,则会唤醒一个被阻塞的线程。

4. 信号量的销毁

int sem_destroy(sem_t *sem);

        功能:销毁信号量,释放相关的系统资源。


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem_WIN;
void* th(void* arg)
{
    sem_wait(&sem_WIN);
    printf("get win\n");
    sleep(rand()%5);
    printf("relese win\n");
    sem_post(&sem_WIN);
    return NULL;
}
void* th1(void* arg)
{
    int i  =10;
    while(i--)
    {
        sem_wait(&sem_H);
        printf("hello ");
        fflush(stdout);
        sem_post(&sem_W);
    }
    return NULL;
}

void* th2(void* arg)
{
    int i  =10;
    while(i--)
    {
        sem_wait(&sem_W);
        printf("world\n");
        sleep(1);
        sem_post(&sem_H);
    }
    return NULL;        
}

int main(int argc, char *argv[])
{
    pthread_t tid1,tid2; 
    sem_init(&sem_H,0,1);
    sem_init(&sem_W,0,0);
    pthread_create(&tid1,NULL,th1,NULL);
    pthread_create(&tid2,NULL,th2,NULL);
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    sem_destroy(&sem_H);//先打印hello,再打印word
    sem_destroy(&sem_W);
//用同步信号量实现10个去三个窗口办业务
    int i = 0 ;
    pthread_t tid[10]={0};
    sem_init(&sem_WIN,0,3);
    for(i=0;i<10;i++)
    {
        pthread_create(&tid[i],NULL,th,NULL);
    }
    for(i=0;i<10;i++)
    {
        pthread_join(tid[i],NULL);
    }
   sem_destroy(&sem_WIN);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值