Thread线程4.线程间共享数据线程安全

  1. 本地状态和共享状态(Local And Shared State)
    (1)Local本地独立
    CLR为每个线程分配自己的内存栈(Stack)以便使本地变量保持独立
    示例:

static void Main(string[] args)
{
new Thread(Go).Start();//在新线程上调用Go()
Go();//在主线程中调用Go()
}
static void Go()
{
   //i是本地变量
   //在每个线程的内存栈上,都会创建i独立副本
   for (int i = 0; i < 5; i++)
   {
      Console.Write("X");
    }
}
//会打印输出10个x

Shared共享
(1).如果多个线程都引用到同一个对象的实例,那么他们就共享了数据

bool _done = true;
 static void Main(string[] args)
{
Program pp = new Program();//创建了一个共同的实例
new Thread(pp.Go).Start();
pp.Go();
}
//由于连个线程是在一个共同实例上调用的Go2(),他们共享_done的值,只会打印一个Done
void Go()
{
  if (_done)
  {
     _done = false;
      Console.WriteLine("Done");
   }
}

打印一次
在这里插入图片描述
(2).被Lambda表达式或匿名委托所捕获的本地变量,会被编辑器转化为字段(fieid),所以也会被共享

bool _isOK = true;
ThreadStart pro = () =>
{
    if (_isOK)
    {
        _isOK = false;
        Console.WriteLine("OK");
    }
};
new Thread(pro).Start();
pro();

打印一次
在这里插入图片描述
(3).静态字段(fieid)也会在线程之间共享数据

 static void Main(string[] args)
{
new Thread(Go).Start();
Go();
}
static void Go()
{
 if (_done2)
  {
   _done2 = false;
   Console.WriteLine("Done");
 }
}

打印一次
在这里插入图片描述

  1. 线程安全
    上面三个例子会引发缺乏线程安全的问题,
    因为打印的输出结果实际上是无法确定的
    有可能会将Done打印两次(理论上)
    如果将IF里面的两条语句的位置调换,那么被打印两次的概率会大大增加
    因为一个语句正在执行输出,还没来得及将Bool的值进行改变
    所以要尽可能避免使用共享状态
 static void Main(string[] args)
{
new Thread(Go).Start();
Go();
}
static void Go4()
{
 if (_done2)
  {
     Console.WriteLine("Done");
  //模拟代码过多时的等待时间
     Thread.Sleep(100);
     _done2 = false;
    }
}

输出两次Done
在这里插入图片描述
3. 解决线程安全问题
(1)在读取和写入共享数据的时候,通过一个互斥锁(exclusive lock) ,就可以修复前面的例子问题
在C#中使用lock语句来加锁
(2)当两个线程同时竞争到一个锁的时候(锁可以基于任何引用类型对象),一个线程会等待或阻塞,知道锁变成可用状态.

		static bool _done;
        static readonly object _loker = new object();

        static void Main(string[] args)
        {
            //在多线程上下文中,以这种方式避免不确定性的代码就叫线程安全
            //Lock不是线程安全的银弹,很容易忘记对字段加锁,lock也会引起一些问题(死锁)
            new Thread(Go).Start();
            Go();
            Console.ReadKey();
        }

        static void Go()
        {
            lock (_loker)
            {
                if (!_done)
                {
                    Console.WriteLine("Done");
                    //模拟代码过多时的等待时间
                    Thread.Sleep(1000);
                    _done = true;
                }
            }

        }

打印一次
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Python中,可以使用threading模块创建线程。在多个线程中共享变量,可以使用Lock对象来保证数据的同步和互斥访问。可以使用threading模块中的Condition对象来实现子线程的休眠与唤醒。 下面是一个示例代码,实现了共享变量、子线程休眠与唤醒的功能: ```python import threading # 共享变量 shared_var = 0 # 创建Lock对象 lock = threading.Lock() # 创建Condition对象 cond = threading.Condition(lock) def worker(): global shared_var while True: with lock: # 判断共享变量是否满足条件 while shared_var < 5: # 如果不满足条件,子线程休眠 cond.wait() # 执行任务 shared_var = 0 print("Worker: shared_var has been reset to 0.") # 唤醒主线程 cond.notify() def main(): global shared_var t = threading.Thread(target=worker) t.start() while True: with lock: # 修改共享变量 shared_var += 1 print("Main: shared_var has been incremented to {}.".format(shared_var)) # 如果共享变量满足条件,唤醒子线程 if shared_var == 5: cond.notify() # 主线程休眠 cond.wait() ``` 在上面的代码中,主线程和子线共享一个变量shared_var。主线程每次增加shared_var的值,当共享变量等于5时,唤醒子线程。子线程判断共享变量是否满足条件,如果不满足条件则休眠,如果满足条件则执行任务并唤醒主线程。通过Lock和Condition对象的配合使用,实现了共享变量和线程之间的同步和互斥访问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值