Linux多线程中fork与互斥锁过程示例

目录
  • 问题提出:
  • (一)初次尝试
  • (二)理性分析
  • (三)解决问题
    • (1)使用pthread_join()
    • (2)使用phread_atfork()注册一个fork之前的判断

问题提出:

我们有这样一个问题:在一个多线程程序中创建子进程并且让子线程子进程去获取一把全局变量的锁,输出子线程得到锁,然后解锁,子进程拿到锁,然后解锁;

(一)初次尝试

代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t mutex;

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);
	printf("fun get lock\n");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
int main()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_create(&id, NULL, fun, NULL);

	sleep(1);
	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);
		printf("child get lock\n");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}

	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	return 0;
}

猜想结果:

理一理思路:

创建一把全局的锁,并初始化

主线程创建子线程,去获取这把锁的同时,主线程休眠一秒,子线程得到这把锁,加锁fun get lock

子线程休眠3秒,输出解锁fun unlock,子线程退出

主线程开始fork,子进程得到这把锁,输出child lock

子进程解锁输出child unlock

父进程的主线程等待子进程的退出,最后销毁锁,输出main over

所以…直接得到正确代码!!!

(二)理性分析

很遗憾,答案是错的!!!

我们先来康康运行结果:正常输出了子线程的内容,但是。。。。卡住了?没错阻塞了。。

再次分析:

阻塞??难道是子进程获取锁时阻塞了?还是父进程等待子进程阻塞了?

或者说:两处地方都阻塞了,子进程获取锁时阻塞,导致父进程阻塞。

验证一下!!

所以程序就是两处地方都阻塞了,子进程获取锁时阻塞,导致父进程阻塞。

(三)解决问题

实际上,我们子线程在获取这把锁并加锁后睡眠3秒,主线程睡眠1秒,在主线程1秒睡眠结束后,开始执行fork,此时的子线程还未解锁正处于睡眠状态,fork过程中,会直接复制父进程的所有资源(**包括这把锁、锁的状态**),没错

就是有两把锁。此时子线程进行了加锁的状态,所以子线程复制的锁也是加锁状态。所以子线程会正常退出,而子进程会因为拿到加锁的锁而阻塞,父进程wait因为子进程阻塞而阻塞;

(1)使用pthread_join()

fork之前使用pthread_join()在子线程结束之前,主线程都将会阻塞,等待子线程结束后,在进行fork,此时子进程得到的锁就是解锁状态

代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t mutex;

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);
	printf("fun get lock\n");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}
int main()
{
	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_create(&id, NULL, fun, NULL);
	pthread_join(id, NULL);

	sleep(1);

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);
		printf("child get lock\n");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}

	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	return 0;
}

结果:

(2)使用phread_atfork()注册一个fork之前的判断

头文件 : pthread.h

int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

prepare : fork执行之前调用该函数

parent : fork执行之后父进程调用该函数

child : fork执行之后子进程调用该函数

返回值: 成功0,失败错误码

代码:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/wait.h>

pthread_mutex_t mutex;

void prepare_fun(void)
{
	pthread_mutex_lock(&mutex);
}

void parent_fun(void)
{
	pthread_mutex_unlock(&mutex);
}

void child_fun()
{
	pthread_mutex_unlock(&mutex);
}

void* fun(void* arg)
{
	pthread_mutex_lock(&mutex);
	printf("fun get lock\n");
	sleep(3);

	pthread_mutex_unlock(&mutex);
	printf("fun unlock\n");
}

int main()
{

	pthread_mutex_init(&mutex, NULL);
	pthread_t id;
	pthread_atfork(prepare_fun, parent_fun, child_fun);
	pthread_create(&id, NULL, fun, NULL);

	sleep(1);

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork err");
		return -1;
	} 

	if(pid == 0)
	{
		pthread_mutex_lock(&mutex);
		printf("child get lock\n");
		sleep(3);

		pthread_mutex_unlock(&mutex);
		printf("child unlock\n");
		exit(0);
	}

	wait(NULL);

	pthread_mutex_destroy(&mutex);
	printf("main over\n");
	return 0;
}

结果:

到此这篇关于Linux多线程中fork与互斥锁过程示例的文章就介绍到这了,更多相关Linux多线程fork与互斥锁内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Linux多线程锁属性设置方法

    互斥锁是Linux下多线程资源保护的常用手段,但是在时序复杂的情况下,很容易会出现死锁的情况. 可以通过设置锁的属性,避免同一条线程重复上锁导致死锁的问题. 通过int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)接口设置 一般是以下四种属性: PTHREAD_MUTEX_NORMAL This type of mutex does not detect deadlock. A thread attempting t

  • 浅谈linux模拟多线程崩溃和多进程崩溃

    结论是: 多线程下如果其中一个线程崩溃了会导致其他线程(整个进程)都崩溃: 多进程下如果其中一个进程崩溃了对其余进程没有影响: 多线程 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <pthread.h> #include <assert.h> void *fun1(void *arg) { printf("fun1 enter\n");

  • Linux多线程环境下 关于进程线程终止函数总结

    pthread_kill: pthread_kill与kill有区别,是向线程发送signal.,大部分signal的默认动作是终止进程的运行,所以,我们才要用signal()去抓信号并加上处理函数. int pthread_kill(pthread_t thread, int sig); 向指定ID的线程发送sig信号,如果线程代码内不做处理,则按照信号默认的行为影响整个进程,也就是说,如果你给一个线程发送了SIGQUIT,但线程却没有实现signal处理函数,则整个进程退出. pthread

  • Linux中多线程详解及简单实例

    Linux中多线程详解及简单实例 1.概念 进程:运行中的程序. 线程:一个程序中的多个执行路径.更准确的定义是:线程是一个进程内部的一个控制序列. 2.为什么要有线程? 用fork调用进程代价太高,需要让一个进程同时做多件事情,线程就非常有用. 3.线程的优点和缺点. 优点: (1)有时,让程序看起来是在同时做两件事是非常有用的. 比如在编辑文档时,还能统计文档里的单词个数. (2)一个混杂着输入.计算.输出的程序,利用线程可以将这3个部 分分成3个线程来执行,从而改变程序执行的性能. (3)

  • Linux多线程中fork与互斥锁过程示例

    目录 问题提出: (一)初次尝试 (二)理性分析 (三)解决问题 (1)使用pthread_join() (2)使用phread_atfork()注册一个fork之前的判断 问题提出: 我们有这样一个问题:在一个多线程程序中创建子进程并且让子线程和子进程去获取一把全局变量的锁,输出子线程得到锁,然后解锁,子进程拿到锁,然后解锁: (一)初次尝试 代码: #include <stdio.h> #include <unistd.h> #include <pthread.h>

  • C#多线程中如何运用互斥锁Mutex

    互斥锁(Mutex) 互斥锁是一个互斥的同步对象,意味着同一时间有且仅有一个线程可以获取它. 互斥锁可适用于一个共享资源每次只能被一个线程访问的情况 函数: //创建一个处于未获取状态的互斥锁 Public Mutex(): //如果owned为true,互斥锁的初始状态就是被主线程所获取,否则处于未获取状态 Public Mutex(bool owned): 如果要获取一个互斥锁.应调用互斥锁上的WaitOne()方法,该方法继承于Thread.WaitHandle类 它处于等到状态直至所调用

  • Python多线程中阻塞(join)与锁(Lock)使用误区解析

    关于阻塞主线程 join的错误用法 Thread.join() 作用为阻塞主线程,即在子线程未返回的时候,主线程等待其返回然后再继续执行. join不能与start在循环里连用 以下为错误代码,代码创建了5个线程,然后用一个循环激活线程,激活之后令其阻塞主线程. threads = [Thread() for i in range(5)] for thread in threads: thread.start() thread.join() 执行过程: 1. 第一次循环中,主线程通过start函

  • 对python多线程中Lock()与RLock()锁详解

    资源总是有限的,程序运行如果对同一个对象进行操作,则有可能造成资源的争用,甚至导致死锁 也可能导致读写混乱 锁提供如下方法: 1.Lock.acquire([blocking]) 2.Lock.release() 3.threading.Lock() 加载线程的锁对象,是一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取 4.threading.RLock() 多重锁,在同一线程中可用被多次acquire.如果使用RLock,那么acquire和release必须成对出现,

  • golang并发安全及读写互斥锁的示例分析

    目录 并发安全和锁 互斥锁 读写互斥锁 并发安全和锁 有时候在Go代码中可能会存在多个goroutine同时操作一个资源(临界区),这种情况会发生竞态问题(数据竞态).类比现实生活中的例子有十字路口被各个方向的的汽车竞争:还有火车上的卫生间被车厢里的人竞争. 举个例子: var x int64 var wg sync.WaitGroup func add() { for i := 0; i < 5000; i++ { x = x + 1 } wg.Done() } func main() { w

  • Python实现的多线程同步与互斥锁功能示例

    本文实例讲述了Python实现的多线程同步与互斥锁功能.分享给大家供大家参考,具体如下: #! /usr/bin/env python #coding=utf-8 import threading import time ''' #1.不加锁 num = 0 class MyThread(threading.Thread): def run(self): global num time.sleep(1) #一定要sleep!!! num = num + 1 msg = self.name + '

  • Java使用synchronized实现互斥锁功能示例

    本文实例讲述了Java使用synchronized实现互斥锁功能.分享给大家供大家参考,具体如下: 代码 package per.thread; import java.io.IOException; public class Test { private int i = 0; private Object object = new Object(); public static void main(String[] args) throws IOException { Test test =

  • 简单掌握Linux系统中fork()函数创建子进程的用法

    fork()函数用于从已存在的进程中创建一个新进程.新进程称为子进程,而园进程称为父进程.使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程的上下文.代码段.进程堆栈.内存信息.打开的文件描述符.符号控制设定.进程优先级.进程组号.当前工作目录.根目录.资源限制和控制终端等,而子进程所独有的只有它的进程号.资源使用和计时器等. 因为子进程几乎是父进程的完全复制,所以父子两进程会运行同一个程序.这就需要用一种方式来区分它们,并使它们照此运行,否则,

  • 一文掌握Go语言并发编程必备的Mutex互斥锁

    目录 1. Mutex 互斥锁的基本概念 2. Mutex 互斥锁的基本用法 3. Mutex 互斥锁的底层实现 3.1 等待队列 3.2 锁状态 4. Mutex 互斥锁的注意事项 4.1 不要将 Mutex 作为函数或方法的参数传递 4.2 不要在获取 Mutex 的锁时阻塞太久 4.3 不要重复释放 Mutex 的锁 4.4 不要在锁内部执行阻塞或耗时操作 5. 总结 在并发编程中,我们需要处理多个线程同时对共享资源的访问问题.如果不加控制地同时访问共享资源,就会导致竞争条件(Race C

  • Python多线程编程(四):使用Lock互斥锁

    前面已经演示了Python:使用threading模块实现多线程编程二两种方式起线程和Python:使用threading模块实现多线程编程三threading.Thread类的重要函数,这两篇文章的示例都是演示了互不相干的独立线程,现在我们考虑这样一个问题:假设各个线程需要访问同一公共资源,我们的代码该怎么写? 复制代码 代码如下: ''' Created on 2012-9-8   @author: walfred @module: thread.ThreadTest3 '''  impor

随机推荐