如何解决多线程编程,子线程的数据源来源于主线程的问题?

必须得开心呀 2018-04-12 11:33:29
大家好!最近又遇到一个新问题。当前主线程A接收各种类型的数据,然后根据数据类型分发给对应的处理模块对数据进行处理。其中,一个模块需要以5Mb/s的速度对数据进行比对,统计等操作(这个模块比较耗时)。然后问题来了,如果让这些模块同步运行,势必会造成界面卡顿,甚至假死的现象。如果使用基于委托的BeginInvoke,速度是有了,界面不会卡,但是由于这个方法本身的回调顺序不确定,我不能采用这种方法。因为我必须按循序处理数据。然后我又采用另开一个线程B处理这个模块,发现这个数据源的问题真的很难解决,因为两个线程异步执行,数据源的更换速度又很快,运行的过程中发现部分数据直接丢失了。后来查了资料,说线程直接最好避免依赖性。但是B线程的数据源必须来源于线程A,而且数据源只能从A获取,无法转到B线程中。今天又查了资料,说还有基于任务的异步,但是其原理我还没有看完,目前还在努力查资料中。
PS:由于这个问题需要急着解决,所以在此发个帖子,希望有朋友知道的可以马上告诉我,可以节省我很多时间,谢谢大家。
...全文
1324 50 打赏 收藏 转发到动态 举报
写回复
用AI写文章
50 条回复
切换为时间正序
请发表友善的回复…
发表回复
cwbdawei 2018-08-07
  • 打赏
  • 举报
回复
不过不知道你具体的需求。就你的描述而言,这样可以实现。
class Program
{
static HighAccurateTimer timer1 = new HighAccurateTimer();
static void Main(string[] args)
{
timer1.Interval = 0.2;
timer1.Elapsed += show;
timer1.Enabled = true;
Console.ReadKey();
}
static int a = 0;
static object locker = new object();
static async void show(object sender, TimerEventArgs e)
{
timer1.Elapsed -= show;
int teamp;
lock (locker)
{
teamp = a;
}
while (teamp < 10)
{
teamp++;
int t = await Task.Run(() => show1(teamp));
}
}
static int show1(int data)
{
Console.WriteLine(data);
return 1;
}
}

qq_38962465 2018-04-13
  • 打赏
  • 举报
回复
你这个就是主线程接收数据,开启一个工作线程处理数据,重要的是你要做好线程同步,因为一个写,一个处理并删除,不做好同步就会出现你说的数据丢失情况。
正怒月神 2018-04-13
  • 打赏
  • 举报
回复
#25正解,不赘述了
  • 打赏
  • 举报
回复
“处理顺序必须一致”这就根本不是并发多线程,这就是思路混乱了。 而“显示顺序不一致”这才是并发多线程处理的本性,你可以在显示的时候保持排序。
  • 打赏
  • 举报
回复
引用 18 楼 youarenotme 的回复:
我使用的这个委托,结果就是保存的顺序不确定,从而我得知处理的顺序也不一致,但我的软件需求是处理顺序必须一致。在问题里我说的两种方式是我目前自己能想到的,但是没法解决根本问题的思路。我想问的是,面对这样的需求,有什么办法可以解决?
当问你结果时你就回答开头,当问你开头时你就说到结尾,总是在回避问题本身。 如果你不需要并发开始多个任务,你的任务必须顺序处理,那么你这个根本就不是并发的逻辑设计问题,你找来一大堆有关“多线程并发处理”的技术来说就无意义了。 你写代码的那一两句话就错了,你发起任务的那1、2条代码就写错了。由于你不贴代码,这就需要你理解然后自己去修改你的代码。
慧眼识狗熊 2018-04-13
  • 打赏
  • 举报
回复
让没轮到的线程等着呗,写个变量标记下当前处理到第几步,等于当前步数的线程执行,大于当前步数的等待。 或者就是List<bool>10个数据,标记之前的是否都处理过,决定当前线程是执行还是等待,一个道理。
  • 打赏
  • 举报
回复
假设你使用 async/await 语法形式,那么你要写
static async Task a()
{

}

static async Task b()
{

}

static async Task c()
{

}

static async void main()
{
    await a();
    await b();
    await c();
}
而你的思维方式是
static async Task a()
{

}

static async Task b()
{

}

static async Task c()
{

}

static async void main()
{
    a();
    b();
    c();
}
这样的。 所以会抄代码的形式不行,要懂得分析实际流程,否则从一开始就入坑了。
秋的红果实 2018-04-13
  • 打赏
  • 举报
回复
典型的async/await问题,可以考虑从这方面入手 如果使用基于委托的BeginInvoke,速度是有了,界面不会卡,但是由于这个方法本身的回调顺序不确定,我不能采用这种方法 ==> 回调顺序决定于你处理业务的耗时,任务完了才能执行回调函数 可以用begininvoke处理一级计算,然后将结果存入有序缓存,然后进行二级计算,…… 说线程直接最好避免依赖性 ==> 胡说,孤立的线程无意义
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
定时器类

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

namespace taskAndAwait
{
    public class TimerEventArgs : EventArgs
    {
        private long clockFrequency;
        public long ClockFrequency
        {
            get { return clockFrequency; }
        }
        private long previousTickCount;
        public long PreviousTickOunt
        {
            get { return previousTickCount; }
        }

        private long currentTickCount;
        public long CurrentTickCount
        {
            get { return currentTickCount; }
        }

        public TimerEventArgs(long clockFreq, long prevTick, long currTick)
        {
            this.clockFrequency = clockFreq;
            this.previousTickCount = prevTick;
            this.currentTickCount = currTick;
        }
    }

    /// <summary>
    /// 高精度定时器事件委托
    /// </summary>
    public delegate void HighTimerEventHandler(object sender, TimerEventArgs e);

    /// <summary>高精度定时器类</summary>
    public class HighAccurateTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out  long lpFrequency);


        public event HighTimerEventHandler Elapsed;

        Thread thread;
        private object threadLock = new object();

        private long clockFrequency = 0;
        private long intevalTicks = 0;
        private long nextTriggerTime = 0;

        private double intervalMs;

        private bool AskExitThread = false;

        /// <summary>
        /// 定时器间隔
        /// </summary>
        public double Interval
        {
            get
            {
                return intervalMs;
            }
            set
            {
                intervalMs = value;

            }
        }

        private bool enable;

        /// <summary>
        /// 启动定时器标志
        /// </summary>
        public bool Enabled
        {
            get
            {
                return enable;
            }
            set
            {
                if (value && enable == false)
                    Start();  //启动线程
                else if (value == false && enable)
                    Destroy();  //关闭定时器

                enable = value;
                if (value == true)
                {
                    intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
                    long currTick = 0;
                    GetTick(out currTick);
                    nextTriggerTime = currTick + intevalTicks;
                }
            }
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public HighAccurateTimer()
        {
            /*
            if (QueryPerformanceFrequency(out clockFrequency) == false)
            {
                return;
            }
            this.intervalMs = 1000;
            this.enable = false;

            thread = new Thread(new ThreadStart(ThreadProc));
            thread.Name = "HighAccuracyTimer";
            thread.Priority = ThreadPriority.Highest;
            thread.Start();
            */

            intervalMs = 1000;
            enable = false;
            QueryPerformanceFrequency(out clockFrequency);
        }

        /// <summary>
        /// 启动线程
        /// </summary>
        public void Start()
        {
            AskExitThread = false;
            if (QueryPerformanceFrequency(out clockFrequency) == false)
            {
                return;
            }
            if (intervalMs == 0)
                this.intervalMs = 1000;
            this.enable = false;

            thread = new Thread(new ThreadStart(ThreadProc));
            thread.Name = "HighAccuracyTimer";
            thread.Priority = ThreadPriority.Highest;
            thread.Start();
        }

        /// <summary>
        /// 进程主程序
        /// </summary>
        private void ThreadProc()
        {
            long currTime;
            GetTick(out currTime);
            nextTriggerTime = currTime + intevalTicks;

            while (true)
            {
                while (currTime < nextTriggerTime)
                {
                    GetTick(out currTime); //决定时钟的精度
                    if (AskExitThread)
                        break;
                }
                nextTriggerTime = currTime + intevalTicks;

                if (Elapsed != null && enable == true)
                {
                    Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
                }

                if (AskExitThread)
                    break;
            }
        }

        /// <summary>
        /// 获得当前时钟计数
        /// </summary>
        /// <param name="currentTickCount">时钟计数</param>
        /// <returns>获得是否成功</returns>
        public bool GetTick(out long currentTickCount)
        {
            if (QueryPerformanceCounter(out currentTickCount) == false)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /// <summary>
        /// 注销定时器
        /// </summary>
        public void Destroy()
        {
            enable = false;
            AskExitThread = true;
            try
            {
                thread.Abort();
            }
            catch { }
        }


    }

}


program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace taskAndAwait
{
    class Program
    {
       static  HighAccurateTimer timer1 = new HighAccurateTimer();
        static void Main(string[] args)
        {
            timer1.Interval = 0.2;
            timer1.Elapsed += show;
            timer1.Enabled = true;
            Console.ReadKey();
        }
        static int a = 0;
        static async void show(object sender, TimerEventArgs e)
        {
            while (a < 10)
            {
                a++;
                int teamp = a;
                int t = await Task.Run(() => show1(teamp));
            }
        }
        static  int show1(int data)
        {
            Console.WriteLine(data);
            return 1;
        }
    }
}
全部代码如上,希望知道解决方法的朋友能为我解惑,谢谢大家!
cheng2005 2018-04-13
  • 打赏
  • 举报
回复
理清你的逻辑,然后再来谈设计。 自己把处理的步骤搞清楚,在纸上画下来,然后分析,哪里必须顺序处理,哪里可以乱序处理。 之后再想程序实现的问题,不然你就是在开车找路,容易开到沟里。
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
截了图也发不了,我这边是内网。
xuzuning 2018-04-13
  • 打赏
  • 举报
回复
如果不是后一个数据的处理要依赖前一个数据处理的结果,而只是想让最终的处理结果有序的排列的话,那至需要再加个结果缓冲区就可以了 你可想想多道下载软件是怎样工作的
token不能为空 2018-04-13
  • 打赏
  • 举报
回复
你这个图片与其用手机拍之后再传给电脑回帖 不如用桌面全屏截图,再用画图工具裁剪一下来得方便呢。。
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
图片不清楚实在不好意思。我晚上再提供一份可复制粘贴的。任务A里面不止获取这一种数据。任务A中是所有数据源的出处,我没法把这些数据的来源分几个地方写。
xuzuning 2018-04-13
  • 打赏
  • 举报
回复
那是什么图?你自己能看清是什么吗?
token不能为空 2018-04-13
  • 打赏
  • 举报
回复
我看明白楼主为了不让程序卡顿,打算把一个耗时任务A分解为a1+a2+a3这种形式 其实直接开一个Task处理任务A不就完事了,如果需要回调直接在 ContineWith 处理是不是可以呢
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
图片看不到吗?我贴的图片就是我写的代码啊。我这边内网,肯定不能提供可复制粘贴的代码啊。
xuzuning 2018-04-13
  • 打赏
  • 举报
回复
你贴的代码在哪里? 一个问题有多种解法! 别人的思路和你的不一样,是不能套用的
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
我贴的代码它的实现思路和我的实际代码是一样的,定时触发那块对应我实例代码不停接收新数据的模块(5mb/s)。
必须得开心呀 2018-04-13
  • 打赏
  • 举报
回复
增加<br /> int temp = a;<br /> showl(a) == > showl(temp)<br /> <br /> <br /> 结果乱序。1到10,只能顺序执行。但如果同步,我的界面会卡死。
加载更多回复(29)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧