欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

多线程、进程锁机制的作用

程序员文章站 2022-06-10 20:49:45
...

为了最大程度上了解锁的机制,此处使用C++来进行编码
(python其实也比较好哈哈哈哈)

以下代码为不加锁的时候的代码,毫无疑问是乱序的,因为两个线程同时操作了全局变量

#include <thread>
#include <iostream>
#include <mutex>
#include <list>
// 全局变量
std::mutex my_mutex;
list<int> L;
// 写入函数
void func1() {
	for (int i = 0; i < 1000; i++) {
		std::cout << "插入的数据为:" << i << std::endl;
		L.push(i);
	}
}
// 读取函数
void func2() {
	for(int i = 0; i < 1000; i++) {
		std::cout << "读取的数据为:" << L.front() << endl;
		L.pop_front();
	}
}
int main(int argc, char const* argv[]) {
	std::thread t1(func1);
	std::thread t2(func2);
	t1.join();
	t2.join();
	return 0;
}

下面有两种加锁方式,一种是全部写入再全部读出

#include <thread>
#include <iostream>
#include <mutex>
#include <list>
// 全局变量
std::mutex my_mutex;
std::list<int> L;
// 写入函数
void func1() {
	std::lock_guard<std::mutex> g1(my_mutex);
	for (int i = 0; i < 1000; i++) {
		std::cout << "插入的数据为:" << i << std::endl;
		L.push_back(i);
	}
}
// 读取函数
void func2() {
	std::lock_guard<std::mutex> g1(my_mutex);
	for (int i = 0; i < 1000; i++) {
		if (!L.empty()) {
			std::cout << "读取的数据为:" << L.front() << std::endl;
			L.pop_front();
		}
	}
}
int main(int argc, char const* argv[]) {
	std::thread t1(func1);
	std::thread t2(func2);
	t1.join();
	t2.join();
	return 0;
}

可以看到,完全没有问题
多线程、进程锁机制的作用
第二种是一边写入一边读出!!

#include <thread>
#include <iostream>
#include <mutex>
#include <list>
// 全局变量
std::mutex my_mutex;
std::list<int> L;
// 写入函数
void func1() {
	// std::lock_guard<std::mutex> g1(my_mutex);
	for (int i = 0; i < 1000; i++) {
		std::cout << "插入的数据为:" << i << std::endl;
		std::lock_guard<std::mutex> g1(my_mutex);
		L.push_back(i);
	}
}
// 读取函数
void func2() {
	// std::lock_guard<std::mutex> g2(my_mutex);
	for (int i = 0; i < 1000; i++) {
		std::lock_guard<std::mutex> g2(my_mutex);
		if (!L.empty()) {
			std::cout << "读取的数据为:" << L.front() << std::endl;
			L.pop_front();
		}
	}
}
int main(int argc, char const* argv[]) {
	std::thread t1(func1);
	std::thread t2(func2);
	t1.join();
	t2.join();
	return 0;
}

这个过程我来稍微解释一下蛤:

  1. 对两个线程进行阻塞,防止主线程执行完之前子线程没有执行完
  2. 第一个子线程在循环内加锁后对全局变量L进行写入一个数据,然后解锁,此时L中有一个数据即1
  3. 全局变量此时是被解锁的被释放的资源,而此时有两个线程是阻塞的状态,在等待事件,而此时L是被释放,而在两个子线程之中都可以对L进行操作,此时就要竞争资源,哪一个线程先运行就先进行加锁和操作再解锁
  4. 依次循环往复,直到竞争的次序已经耗尽,所以线程结束。
  5. 注意:线程在竞争资源的时候线程也是在运行的,只是阻塞的时候在等待事件,如果竞争成功了可以进入加锁,没有竞争成功只有失去了这一次机会,每次只有一个线程可以向前执行

之前看到一句话挺有道理:
如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态,第一个变为运行状态的线程可以对互斥量加锁,其他线程将会看到互斥锁依然被锁住,只能回去再次等待它重新变为可用。在这种方式下,每次只有一个线程可以向前执行

python的话我也不介意写一下
第一种情况

from threading import Thread
from threading import Lock
from queue import Queue

# 定义全局变量
list_thread = []
lock = Lock()


def func1():
    lock.acquire()
    for i in range(100):
        list_thread.append(i)
        print("插入的数据为:", i)
    lock.release()


def func2():
    lock.acquire()
    for i in range(100):
        num = list_thread[-1]
        list_thread.pop(i)
        print("删除的数据为:", num)
    lock.release()


def main():
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)
    

if __name__ == '__main__':
    main()

第二种情况

from threading import Thread
from threading import Lock
from queue import Queue

# 定义全局变量
list_thread = []
lock = Lock()


def func1():
    # lock.acquire()
    for i in range(100):
        lock.acquire()
        list_thread.append(i)
        lock.release()
        print("插入的数据为:", i)
    # lock.release()


def func2():
    # lock.acquire()
    for i in range(100):
        lock.acquire()
        num = list_thread[-1]
        list_thread.pop(i)
        lock.release()
        print("删除的数据为:", num)
    # lock.release()


def main():
    t1 = Thread(target=func1)
    t2 = Thread(target=func2)


if __name__ == '__main__':
    main()

但是python里面有个好东西可以解决加锁的问题,queue。

简单的来说就是多线程需要加锁,很可能会造成死锁,而queue自带锁。所以多线程结合queue会好的很多

queue可以传递多线程的结果,用以代替return

import threading
import time;
from queue import Queue 
 
def job(vec,res):
  for i in range(len(vec)):
    vec[i] = vec[i]*2
  res.put(vec)
 
def main():
  res = Queue()
  data=[[1,2,3],[3,4,5],[2,2,2],[3,3,3]]
  for i in range(len(data)):
    t=threading.Thread(target=job,args=(data[i],res)) 
    t.start()
    t.join()
 
  result =[]
  for j in range(len(data)):
    result.append(res.get())
  print(result)
 
 
if __name__ == '__main__':
    main()
[[2, 4, 6], [6, 8, 10], [4, 4, 4], [6, 6, 6]]