안 용태

안 용태

1607568000

[앱개발] [Flutter] Flutter 개발자는 무조건 알아야 하는 GetX [#1-Navigation]

Flutter GetX 라이브러리에 대한 강의입니다. 이번 강의는 GetX의 Navigation 기능 및 Snackbar, Dialog, BottomSheet 에 대해 알아보았습니다.

[GitHub]
https://github.com/serendipity1004/Youtube-Flutter-Tutorials

#flutter #dart #mobile-apps #programming #developer

What is GEEK

Buddha Community

[앱개발] [Flutter] Flutter 개발자는 무조건 알아야 하는 GetX [#1-Navigation]

Google's Flutter 1.20 stable announced with new features - Navoki

Flutter Google cross-platform UI framework has released a new version 1.20 stable.

Flutter is Google’s UI framework to make apps for Android, iOS, Web, Windows, Mac, Linux, and Fuchsia OS. Since the last 2 years, the flutter Framework has already achieved popularity among mobile developers to develop Android and iOS apps. In the last few releases, Flutter also added the support of making web applications and desktop applications.

Last month they introduced the support of the Linux desktop app that can be distributed through Canonical Snap Store(Snapcraft), this enables the developers to publish there Linux desktop app for their users and publish on Snap Store.  If you want to learn how to Publish Flutter Desktop app in Snap Store that here is the tutorial.

Flutter 1.20 Framework is built on Google’s made Dart programming language that is a cross-platform language providing native performance, new UI widgets, and other more features for the developer usage.

Here are the few key points of this release:

Performance improvements for Flutter and Dart

In this release, they have got multiple performance improvements in the Dart language itself. A new improvement is to reduce the app size in the release versions of the app. Another performance improvement is to reduce junk in the display of app animation by using the warm-up phase.

sksl_warm-up

If your app is junk information during the first run then the Skia Shading Language shader provides for pre-compilation as part of your app’s build. This can speed it up by more than 2x.

Added a better support of mouse cursors for web and desktop flutter app,. Now many widgets will show cursor on top of them or you can specify the type of supported cursor you want.

Autofill for mobile text fields

Autofill was already supported in native applications now its been added to the Flutter SDK. Now prefilled information stored by your OS can be used for autofill in the application. This feature will be available soon on the flutter web.

flutter_autofill

A new widget for interaction

InteractiveViewer is a new widget design for common interactions in your app like pan, zoom drag and drop for resizing the widget. Informations on this you can check more on this API documentation where you can try this widget on the DartPad. In this release, drag-drop has more features added like you can know precisely where the drop happened and get the position.

Updated Material Slider, RangeSlider, TimePicker, and DatePicker

In this new release, there are many pre-existing widgets that were updated to match the latest material guidelines, these updates include better interaction with Slider and RangeSliderDatePicker with support for date range and time picker with the new style.

flutter_DatePicker

New pubspec.yaml format

Other than these widget updates there is some update within the project also like in pubspec.yaml file format. If you are a flutter plugin publisher then your old pubspec.yaml  is no longer supported to publish a plugin as the older format does not specify for which platform plugin you are making. All existing plugin will continue to work with flutter apps but you should make a plugin update as soon as possible.

Preview of embedded Dart DevTools in Visual Studio Code

Visual Studio code flutter extension got an update in this release. You get a preview of new features where you can analyze that Dev tools in your coding workspace. Enable this feature in your vs code by _dart.previewEmbeddedDevTools_setting. Dart DevTools menu you can choose your favorite page embed on your code workspace.

Network tracking

The updated the Dev tools comes with the network page that enables network profiling. You can track the timings and other information like status and content type of your** network calls** within your app. You can also monitor gRPC traffic.

Generate type-safe platform channels for platform interop

Pigeon is a command-line tool that will generate types of safe platform channels without adding additional dependencies. With this instead of manually matching method strings on platform channel and serializing arguments, you can invoke native class and pass nonprimitive data objects by directly calling the Dartmethod.

There is still a long list of updates in the new version of Flutter 1.2 that we cannot cover in this blog. You can get more details you can visit the official site to know more. Also, you can subscribe to the Navoki newsletter to get updates on these features and upcoming new updates and lessons. In upcoming new versions, we might see more new features and improvements.

You can get more free Flutter tutorials you can follow these courses:

#dart #developers #flutter #app developed #dart devtools in visual studio code #firebase local emulator suite in flutter #flutter autofill #flutter date picker #flutter desktop linux app build and publish on snapcraft store #flutter pigeon #flutter range slider #flutter slider #flutter time picker #flutter tutorial #flutter widget #google flutter #linux #navoki #pubspec format #setup flutter desktop on windows

A Wrapper for Sembast and SQFlite to Enable Easy

FHIR_DB

This is really just a wrapper around Sembast_SQFLite - so all of the heavy lifting was done by Alex Tekartik. I highly recommend that if you have any questions about working with this package that you take a look at Sembast. He's also just a super nice guy, and even answered a question for me when I was deciding which sembast version to use. As usual, ResoCoder also has a good tutorial.

I have an interest in low-resource settings and thus a specific reason to be able to store data offline. To encourage this use, there are a number of other packages I have created based around the data format FHIR. FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7.

Using the Db

So, while not absolutely necessary, I highly recommend that you use some sort of interface class. This adds the benefit of more easily handling errors, plus if you change to a different database in the future, you don't have to change the rest of your app, just the interface.

I've used something like this in my projects:

class IFhirDb {
  IFhirDb();
  final ResourceDao resourceDao = ResourceDao();

  Future<Either<DbFailure, Resource>> save(Resource resource) async {
    Resource resultResource;
    try {
      resultResource = await resourceDao.save(resource);
    } catch (error) {
      return left(DbFailure.unableToSave(error: error.toString()));
    }
    return right(resultResource);
  }

  Future<Either<DbFailure, List<Resource>>> returnListOfSingleResourceType(
      String resourceType) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.getAllSortedById(resourceType: resourceType);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }

  Future<Either<DbFailure, List<Resource>>> searchFunction(
      String resourceType, String searchString, String reference) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.searchFor(resourceType, searchString, reference);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }
}

I like this because in case there's an i/o error or something, it won't crash your app. Then, you can call this interface in your app like the following:

final patient = Patient(
    resourceType: 'Patient',
    name: [HumanName(text: 'New Patient Name')],
    birthDate: Date(DateTime.now()),
);

final saveResult = await IFhirDb().save(patient);

This will save your newly created patient to the locally embedded database.

IMPORTANT: this database will expect that all previously created resources have an id. When you save a resource, it will check to see if that resource type has already been stored. (Each resource type is saved in it's own store in the database). It will then check if there is an ID. If there's no ID, it will create a new one for that resource (along with metadata on version number and creation time). It will save it, and return the resource. If it already has an ID, it will copy the the old version of the resource into a _history store. It will then update the metadata of the new resource and save that version into the appropriate store for that resource. If, for instance, we have a previously created patient:

{
    "resourceType": "Patient",
    "id": "fhirfli-294057507-6811107",
    "meta": {
        "versionId": "1",
        "lastUpdated": "2020-10-16T19:41:28.054369Z"
    },
    "name": [
        {
            "given": ["New"],
            "family": "Patient"
        }
    ],
    "birthDate": "2020-10-16"
}

And we update the last name to 'Provider'. The above version of the patient will be kept in _history, while in the 'Patient' store in the db, we will have the updated version:

{
    "resourceType": "Patient",
    "id": "fhirfli-294057507-6811107",
    "meta": {
        "versionId": "2",
        "lastUpdated": "2020-10-16T19:45:07.316698Z"
    },
    "name": [
        {
            "given": ["New"],
            "family": "Provider"
        }
    ],
    "birthDate": "2020-10-16"
}

This way we can keep track of all previous version of all resources (which is obviously important in medicine).

For most of the interactions (saving, deleting, etc), they work the way you'd expect. The only difference is search. Because Sembast is NoSQL, we can search on any of the fields in a resource. If in our interface class, we have the following function:

  Future<Either<DbFailure, List<Resource>>> searchFunction(
      String resourceType, String searchString, String reference) async {
    List<Resource> resultList;
    try {
      resultList =
          await resourceDao.searchFor(resourceType, searchString, reference);
    } catch (error) {
      return left(DbFailure.unableToObtainList(error: error.toString()));
    }
    return right(resultList);
  }

You can search for all immunizations of a certain patient:

searchFunction(
        'Immunization', 'patient.reference', 'Patient/$patientId');

This function will search through all entries in the 'Immunization' store. It will look at all 'patient.reference' fields, and return any that match 'Patient/$patientId'.

The last thing I'll mention is that this is a password protected db, using AES-256 encryption (although it can also use Salsa20). Anytime you use the db, you have the option of using a password for encryption/decryption. Remember, if you setup the database using encryption, you will only be able to access it using that same password. When you're ready to change the password, you will need to call the update password function. If we again assume we created a change password method in our interface, it might look something like this:

class IFhirDb {
  IFhirDb();
  final ResourceDao resourceDao = ResourceDao();
  ...
    Future<Either<DbFailure, Unit>> updatePassword(String oldPassword, String newPassword) async {
    try {
      await resourceDao.updatePw(oldPassword, newPassword);
    } catch (error) {
      return left(DbFailure.unableToUpdatePassword(error: error.toString()));
    }
    return right(Unit);
  }

You don't have to use a password, and in that case, it will save the db file as plain text. If you want to add a password later, it will encrypt it at that time.

General Store

After using this for a while in an app, I've realized that it needs to be able to store data apart from just FHIR resources, at least on occasion. For this, I've added a second class for all versions of the database called GeneralDao. This is similar to the ResourceDao, but fewer options. So, in order to save something, it would look like this:

await GeneralDao().save('password', {'new':'map'});
await GeneralDao().save('password', {'new':'map'}, 'key');

The difference between these two options is that the first one will generate a key for the map being stored, while the second will store the map using the key provided. Both will return the key after successfully storing the map.

Other functions available include:

// deletes everything in the general store
await GeneralDao().deleteAllGeneral('password'); 

// delete specific entry
await GeneralDao().delete('password','key'); 

// returns map with that key
await GeneralDao().find('password', 'key'); 

FHIR® is a registered trademark of Health Level Seven International (HL7) and its use does not constitute an endorsement of products by HL7®

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add fhir_db

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  fhir_db: ^0.4.3

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:fhir_db/dstu2.dart';
import 'package:fhir_db/dstu2/fhir_db.dart';
import 'package:fhir_db/dstu2/general_dao.dart';
import 'package:fhir_db/dstu2/resource_dao.dart';
import 'package:fhir_db/encrypt/aes.dart';
import 'package:fhir_db/encrypt/salsa.dart';
import 'package:fhir_db/r4.dart';
import 'package:fhir_db/r4/fhir_db.dart';
import 'package:fhir_db/r4/general_dao.dart';
import 'package:fhir_db/r4/resource_dao.dart';
import 'package:fhir_db/r5.dart';
import 'package:fhir_db/r5/fhir_db.dart';
import 'package:fhir_db/r5/general_dao.dart';
import 'package:fhir_db/r5/resource_dao.dart';
import 'package:fhir_db/stu3.dart';
import 'package:fhir_db/stu3/fhir_db.dart';
import 'package:fhir_db/stu3/general_dao.dart';
import 'package:fhir_db/stu3/resource_dao.dart'; 

example/lib/main.dart

import 'package:fhir/r4.dart';
import 'package:fhir_db/r4.dart';
import 'package:flutter/material.dart';
import 'package:test/test.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final resourceDao = ResourceDao();

  // await resourceDao.updatePw('newPw', null);
  await resourceDao.deleteAllResources(null);

  group('Playing with passwords', () {
    test('Playing with Passwords', () async {
      final patient = Patient(id: Id('1'));

      final saved = await resourceDao.save(null, patient);

      await resourceDao.updatePw(null, 'newPw');
      final search1 = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search1[0]);

      await resourceDao.updatePw('newPw', 'newerPw');
      final search2 = await resourceDao.find('newerPw',
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search2[0]);

      await resourceDao.updatePw('newerPw', null);
      final search3 = await resourceDao.find(null,
          resourceType: R4ResourceType.Patient, id: Id('1'));
      expect(saved, search3[0]);

      await resourceDao.deleteAllResources(null);
    });
  });

  final id = Id('12345');
  group('Saving Things:', () {
    test('Save Patient', () async {
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);
      final patient = Patient(id: id, name: [humanName]);
      final saved = await resourceDao.save(null, patient);

      expect(saved.id, id);

      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      final organization = Organization(id: id, name: 'FhirFli');
      final saved = await resourceDao.save(null, organization);

      expect(saved.id, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final observation1 = Observation(
        id: Id('obs1'),
        code: CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      final observation1 = Observation(
          id: Id('obs1'),
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final saved = await resourceDao.save(null, observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, Id('2'));
    });

    test('Save Observation2', () async {
      final observation2 = Observation(
        id: Id('obs2'),
        code: CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation2);

      expect(saved.id, Id('obs2'));

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final observation3 = Observation(
        id: Id('obs3'),
        code: CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save(null, observation3);

      expect(saved.id, Id('obs3'));

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Finding Things:', () {
    test('Find 1st Patient', () async {
      final search = await resourceDao.find(null,
          resourceType: R4ResourceType.Patient, id: id);
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final search = await resourceDao.find(null,
          resourceType: R4ResourceType.Observation, id: Id('obs3'));

      expect(search.length, 1);

      expect(search[0].id, Id('obs3'));

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final search = await resourceDao.getResourceType(
        null,
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 3);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final search = await resourceDao.getAll(null);

      expect(search.length, 5);
      final patList = search.toList();
      final orgList = search.toList();
      final obsList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 1);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await resourceDao.delete(
          null, null, R4ResourceType.Observation, Id('obs2'), null, null);

      final search = await resourceDao.getResourceType(
        null,
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 2);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await resourceDao.deleteSingleType(null,
          resourceType: R4ResourceType.Observation);

      final search = await resourceDao.getAll(null);

      expect(search.length, 2);

      final patList = search.toList();
      final orgList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 1);

      expect(patList.length, 1);
    });

    test('Delete All Resources', () async {
      await resourceDao.deleteAllResources(null);

      final search = await resourceDao.getAll(null);

      expect(search.length, 0);
    });
  });

  group('Password - Saving Things:', () {
    test('Save Patient', () async {
      await resourceDao.updatePw(null, 'newPw');
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);
      final patient = Patient(id: id, name: [humanName]);
      final saved = await resourceDao.save('newPw', patient);

      expect(saved.id, id);

      expect((saved as Patient).name?[0], humanName);
    });

    test('Save Organization', () async {
      final organization = Organization(id: id, name: 'FhirFli');
      final saved = await resourceDao.save('newPw', organization);

      expect(saved.id, id);

      expect((saved as Organization).name, 'FhirFli');
    });

    test('Save Observation1', () async {
      final observation1 = Observation(
        id: Id('obs1'),
        code: CodeableConcept(text: 'Observation #1'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1');
    });

    test('Save Observation1 Again', () async {
      final observation1 = Observation(
          id: Id('obs1'),
          code: CodeableConcept(text: 'Observation #1 - Updated'));
      final saved = await resourceDao.save('newPw', observation1);

      expect(saved.id, Id('obs1'));

      expect((saved as Observation).code.text, 'Observation #1 - Updated');

      expect(saved.meta?.versionId, Id('2'));
    });

    test('Save Observation2', () async {
      final observation2 = Observation(
        id: Id('obs2'),
        code: CodeableConcept(text: 'Observation #2'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation2);

      expect(saved.id, Id('obs2'));

      expect((saved as Observation).code.text, 'Observation #2');
    });

    test('Save Observation3', () async {
      final observation3 = Observation(
        id: Id('obs3'),
        code: CodeableConcept(text: 'Observation #3'),
        effectiveDateTime: FhirDateTime(DateTime(1981, 09, 18)),
      );
      final saved = await resourceDao.save('newPw', observation3);

      expect(saved.id, Id('obs3'));

      expect((saved as Observation).code.text, 'Observation #3');
    });
  });

  group('Password - Finding Things:', () {
    test('Find 1st Patient', () async {
      final search = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Patient, id: id);
      final humanName = HumanName(family: 'Atreides', given: ['Duke']);

      expect(search.length, 1);

      expect((search[0] as Patient).name?[0], humanName);
    });

    test('Find 3rd Observation', () async {
      final search = await resourceDao.find('newPw',
          resourceType: R4ResourceType.Observation, id: Id('obs3'));

      expect(search.length, 1);

      expect(search[0].id, Id('obs3'));

      expect((search[0] as Observation).code.text, 'Observation #3');
    });

    test('Find All Observations', () async {
      final search = await resourceDao.getResourceType(
        'newPw',
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 3);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), true);

      expect(idList.contains('obs3'), true);
    });

    test('Find All (non-historical) Resources', () async {
      final search = await resourceDao.getAll('newPw');

      expect(search.length, 5);
      final patList = search.toList();
      final orgList = search.toList();
      final obsList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);
      obsList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Observation);

      expect(patList.length, 1);

      expect(orgList.length, 1);

      expect(obsList.length, 3);
    });
  });

  group('Password - Deleting Things:', () {
    test('Delete 2nd Observation', () async {
      await resourceDao.delete(
          'newPw', null, R4ResourceType.Observation, Id('obs2'), null, null);

      final search = await resourceDao.getResourceType(
        'newPw',
        resourceTypes: [R4ResourceType.Observation],
      );

      expect(search.length, 2);

      final idList = [];
      for (final obs in search) {
        idList.add(obs.id.toString());
      }

      expect(idList.contains('obs1'), true);

      expect(idList.contains('obs2'), false);

      expect(idList.contains('obs3'), true);
    });

    test('Delete All Observations', () async {
      await resourceDao.deleteSingleType('newPw',
          resourceType: R4ResourceType.Observation);

      final search = await resourceDao.getAll('newPw');

      expect(search.length, 2);

      final patList = search.toList();
      final orgList = search.toList();
      patList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Patient);
      orgList.retainWhere(
          (resource) => resource.resourceType == R4ResourceType.Organization);

      expect(patList.length, 1);

      expect(patList.length, 1);
    });

    test('Delete All Resources', () async {
      await resourceDao.deleteAllResources('newPw');

      final search = await resourceDao.getAll('newPw');

      expect(search.length, 0);

      await resourceDao.updatePw('newPw', null);
    });
  });
} 

Download Details:

Author: MayJuun

Source Code: https://github.com/MayJuun/fhir/tree/main/fhir_db

#sqflite  #dart  #flutter 

Terry  Tremblay

Terry Tremblay

1598396940

What is Flutter and why you should learn it?

Flutter is an open-source UI toolkit for mobile developers, so they can use it to build native-looking** Android and iOS** applications from the same code base for both platforms. Flutter is also working to make Flutter apps for Web, PWA (progressive Web-App) and Desktop platform (Windows,macOS,Linux).

flutter-mobile-desktop-web-embedded_min

Flutter was officially released in December 2018. Since then, it has gone a much stronger flutter community.

There has been much increase in flutter developers, flutter packages, youtube tutorials, blogs, flutter examples apps, official and private events, and more. Flutter is now on top software repos based and trending on GitHub.

Flutter meaning?

What is Flutter? this question comes to many new developer’s mind.

humming_bird_dart_flutter

Flutter means flying wings quickly, and lightly but obviously, this doesn’t apply in our SDK.

So Flutter was one of the companies that were acquired by **Google **for around $40 million. That company was based on providing gesture detection and recognition from a standard webcam. But later when the Flutter was going to release in alpha version for developer it’s name was Sky, but since Google already owned Flutter name, so they rename it to Flutter.

Where Flutter is used?

Flutter is used in many startup companies nowadays, and even some MNCs are also adopting Flutter as a mobile development framework. Many top famous companies are using their apps in Flutter. Some of them here are

Dream11

Dream11

NuBank

NuBank

Reflectly app

Reflectly app

Abbey Road Studios

Abbey Road Studios

and many more other apps. Mobile development companies also adopted Flutter as a service for their clients. Even I was one of them who developed flutter apps as a freelancer and later as an IT company for mobile apps.

Flutter as a service

#dart #flutter #uncategorized #flutter framework #flutter jobs #flutter language #flutter meaning #flutter meaning in hindi #google flutter #how does flutter work #what is flutter

伊藤  直子

伊藤 直子

1633693200

【 初心者向け】C言語でのマルチスレッド の概要

ニューヨークで働き、ウォール街中のプログラマーと話をしていると、ほとんどのリアルタイムプログラミングアプリケーションで期待される共通の知識の糸に気づきました。その知識はマルチスレッドとして知られています。私はプログラミングの世界を移動し、潜在的なプログラミング候補者にインタビューを行ったので、マルチスレッドについてほとんど知られていないことや、スレッドが適用される理由や方法に驚かされることは決してありません。Vance Morrisonによって書かれた一連の優れた記事で、MSDNはこの問題に対処しようとしました:(MSDNの8月号、すべての開発者がマルチスレッドアプリについて知っておくべきこと、および10月号はマルチスレッドでのローロック技術の影響を理解するを参照してください)。アプリ

この記事では、スレッド化、スレッド化が使用される理由、および.NETでのスレッド化の使用方法について紹介します。マルチスレッドの背後にある謎を完全に明らかにし、それを説明する際に、コード内の潜在的なスレッド障害を回避するのに役立つことを願っています。

スレッドとは何ですか?

すべてのアプリケーションは、少なくとも1つのスレッドで実行されます。では、スレッドとは何ですか?スレッドはプロセスにすぎません。私の推測では、糸という言葉は、織機で糸を織り上げる超自然的なミューズのギリシャ神話に由来していると思います。各糸は、誰かの人生の時間の道を表しています。あなたがその糸をいじると、あなたは人生の構造を乱したり、人生のプロセスを変えたりします。コンピューターでは、スレッドは時間の経過とともに移動するプロセスです。プロセスは一連の順次ステップを実行し、各ステップはコード行を実行します。ステップは連続しているため、各ステップには一定の時間がかかります。一連のステップを完了するのにかかる時間は、各プログラミングステップの実行にかかる時間の合計です。

マルチスレッドアプリケーションとは何ですか?

長い間、ほとんどのプログラミングアプリケーション(組み込みシステムプログラムを除く)はシングルスレッドでした。これは、アプリケーション全体でスレッドが1つしかないことを意味します。計算Bが完了するまで、計算Aを実行することはできません。プログラムはステップ1から始まり、最後のステップ(ステップ10と呼びます)に到達するまで順次続行します(ステップ2、ステップ3、ステップ4)。マルチスレッドアプリケーションを使用すると、複数のスレッドを実行できます。各スレッドは独自のプロセスで実行されます。したがって、理論的には、あるスレッドでステップ1を実行し、同時に別のスレッドでステップ2を実行できます。同時に、ステップ3を独自のスレッドで実行し、ステップ4を独自のスレッドで実行することもできます。したがって、ステップ1、ステップ2、ステップ3、およびステップ4は同時に実行されます。理論的には、4つのステップすべてがほぼ同時にかかった場合、シングルスレッドの実行にかかる時間の4分の1でプログラムを終了できます(4プロセッサマシンを使用していると仮定)。では、なぜすべてのプログラムがマルチスレッド化されていないのでしょうか。スピードとともに、あなたは複雑さに直面するからです。ステップ1がステップ2の情報に何らかの形で依存している場合を想像してみてください。ステップ1がステップ2の前に計算を終了した場合、またはその逆の場合、プログラムが正しく実行されない可能性があります。

珍しいアナロジー

マルチスレッドを考える別の方法は、人体を考慮することです。体の各器官(心臓、肺、肝臓、脳)はすべてプロセスに関与しています。各プロセスは同時に実行されています。各臓器がプロセスのステップとして実行された場合を想像してみてください。最初に心臓、次に脳、次に肝臓、次に肺です。私たちはおそらく死んでしまうでしょう。つまり、人体は1つの大きなマルチスレッドアプリケーションのようなものです。すべての臓器は同時に実行されるプロセスであり、これらのプロセスはすべて相互に依存しています。これらのプロセスはすべて、神経信号、血流、化学的トリガーを介して通信します。すべてのマルチスレッドアプリケーションと同様に、人体は非常に複雑です。一部のプロセスが他のプロセスから情報を取得しない場合、または特定のプロセスが遅くなったり速くなったりすると、医学的な問題が発生します。それか'

いつスレッド化するか

マルチスレッドは、プログラムをより効率的に実行したい状況で最もよく使用されます。たとえば、ウィンドウフォームプログラムの中に、実行に1秒以上かかり、繰り返し実行する必要のあるメソッド(method_Aと呼びます)が含まれているとします。プログラム全体が単一のスレッドで実行された場合、ボタンの押下が正しく機能しなかったり、入力が少し遅くなったりすることがあります。method_Aの計算量が多すぎると、ウィンドウフォームの特定の部分がまったく機能しないことに気付くかもしれません。この許容できないプログラムの動作は、プログラムにマルチスレッドが必要であることを示しています。スレッド化が必要になるもう1つの一般的なシナリオは、メッセージングシステムです。アプリケーションに多数のメッセージが送信されている場合は、メインの処理プログラムの実行と同時にそれらをキャプチャし、適切に配布する必要があります。重い処理を実行しているときに一連のメッセージを効率的にキャプチャすることはできません。そうしないと、メッセージを見逃す可能性があります。複数のスレッドは、複数のプロセスが同時に実行される組立ライン方式で使用することもできます。たとえば、プロセスがスレッドでデータを収集すると、1つのプロセスがデータをフィルタリングし、1つのプロセスがデータをデータベースと照合します。これらの各シナリオはマルチスレッドの一般的な使用法であり、シングルスレッドで実行されている同様のアプリケーションのパフォーマンスを大幅に向上させます。そうしないと、メッセージを見逃す可能性があるためです。複数のスレッドは、複数のプロセスが同時に実行される組立ライン方式で使用することもできます。たとえば、プロセスがスレッドでデータを収集すると、1つのプロセスがデータをフィルタリングし、1つのプロセスがデータをデータベースと照合します。これらの各シナリオはマルチスレッドの一般的な使用法であり、シングルスレッドで実行されている同様のアプリケーションのパフォーマンスを大幅に向上させます。そうしないと、メッセージを見逃す可能性があるためです。複数のスレッドは、複数のプロセスが同時に実行される組立ライン方式で使用することもできます。たとえば、プロセスがスレッドでデータを収集すると、1つのプロセスがデータをフィルタリングし、1つのプロセスがデータをデータベースと照合します。これらの各シナリオはマルチスレッドの一般的な使用法であり、シングルスレッドで実行されている同様のアプリケーションのパフォーマンスを大幅に向上させます。

スレッドしない場合

初心者のプログラマーが最初にスレッド化を学ぶとき、彼らはプログラムでスレッド化を使用する可能性に魅了される可能性があります。彼らは実際にスレッドハッピーになるかもしれません  詳しく説明させてください、

1日目)プログラマーは、スレッドを生成できることを学び、プログラムで1つの新しいスレッドCool!の作成を開始します 。

2日目)プログラマーは、「プログラムの一部で他のスレッドを生成することで、これをさらに効率的にすることができます!」と言います。

3日目)P:「わあ、スレッド内でスレッドをフォークすることもでき、本当に効率が向上します!!」

4日目)P:「奇妙な結果が出ているようですが、それは問題ありません。今は無視します。」

5日目)「うーん、widgetX変数に値がある場合もありますが、まったく設定されていないように見える場合もあります。コンピューターが機能していないため、デバッガーを実行するだけです」。

9日目)「このくそったれ(より強い言語)プログラムはあちこちでジャンプしています!!何が起こっているのか理解できません!」

2週目)時々、プログラムはただそこに座って、まったく何もしません!ヘルプ!!!!!

おなじみですか?マルチスレッドプログラムを初めて設計しようとしたほとんどの人は、スレッドの設計知識が豊富であっても、おそらくこれらの毎日の箇条書きの少なくとも1つまたは2つを経験したことがあります。スレッド化が悪いことだとほのめかしているわけではありません。プログラムでスレッド化の効率を上げるプロセスでは、非常に注意してください。  シングルスレッドプログラムとは異なり、同時に多くのプロセスを処理しているため、複数の従属変数を持つ複数のプロセスを追跡するのは非常に難しい場合があります。ジャグリングと同じようにマルチスレッドを考えてください。手で1つのボールをジャグリングするのは(退屈ではありますが)かなり簡単です。ただし、これらのボールのうち2つを空中に置くように挑戦された場合、その作業は少し難しくなります。3、4、および5の場合、ボールは次第に難しくなります。ボールの数が増えると、実際にボールを落とす可能性が高くなります。 一度にたくさんのボールをジャグリングするには、知識、スキル、正確なタイミングが必要です。マルチスレッドもそうです。 

マルチスレッド

図1-マルチスレッドはジャグリングプロセスのようなものです

 
スレッディングの問題

プログラム内のすべてのプロセスが相互に排他的である場合、つまり、プロセスが他のプロセスにまったく依存していない場合、複数のスレッド化は非常に簡単で、問題はほとんど発生しません。各プロセスは、他のプロセスに煩わされることなく、独自のハッピーコースで実行されます。ただし、複数のプロセスが他のプロセスによって使用されているメモリの読み取りまたは書き込みを行う必要がある場合、問題が発生する可能性があります。たとえば、プロセス#1とプロセス#2の2つのプロセスがあるとします。両方のプロセスが変数Xを共有します。スレッドプロセス#1が最初に値5の変数Xを書き込み、スレッドプロセス#2が次に値-3の変数Xを書き込む場合、Xの最終値は-3です。ただし、プロセス#2が最初に値-3の変数Xを書き込み、次にプロセス#1が値5の変数Xを書き込む場合、Xの最終値は5です。Xを設定できるプロセスがプロセス#1またはプロセス#2の知識を持っていない場合、Xは、最初にXに到達したスレッドに応じて異なる最終値になる可能性があります。シングルスレッドプログラムでは、すべてが順番に続くため、これが発生する可能性はありません。シングルスレッドプログラムでは、並列に実行されているプロセスがないため、Xは常に最初にメソッド#1によって設定され(最初に呼び出された場合)、次にメソッド#2によって設定されます。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。Xは、どのスレッドが最初にXに到達したかによって、最終的に異なる最終値になる可能性があります。シングルスレッドプログラムでは、すべてが順番に続くため、これが発生する可能性はありません。シングルスレッドプログラムでは、並列に実行されているプロセスがないため、Xは常に最初にメソッド#1によって設定され(最初に呼び出された場合)、次にメソッド#2によって設定されます。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。Xは、どのスレッドが最初にXに到達したかによって、最終的に異なる最終値になる可能性があります。シングルスレッドプログラムでは、すべてが順番に続くため、これが発生する可能性はありません。シングルスレッドプログラムでは、並列に実行されているプロセスがないため、Xは常に最初にメソッド#1によって設定され(最初に呼び出された場合)、次にメソッド#2によって設定されます。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。すべてが順番に続くため、これが発生する可能性はありません。シングルスレッドプログラムでは、並列に実行されているプロセスがないため、Xは常に最初にメソッド#1によって設定され(最初に呼び出された場合)、次にメソッド#2によって設定されます。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。すべてが順番に続くため、これが発生する可能性はありません。シングルスレッドプログラムでは、並列に実行されているプロセスがないため、Xは常に最初にメソッド#1によって設定され(最初に呼び出された場合)、次にメソッド#2によって設定されます。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。(最初に呼び出された場合)次に、メソッド#2で設定します。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。(最初に呼び出された場合)次に、メソッド#2で設定します。シングルスレッドプログラムには驚きはありません。それはステップバイステップです。マルチスレッドプログラムを使用すると、2つのスレッドが同時にコードを入力し、結果に大混乱をもたらす可能性があります。スレッドの問題は、同時に実行されている別のスレッドが同じコードを入力して共有データを操作できるようにしながら、共有メモリにアクセスする1つのスレッドを制御する何らかの方法が必要なことです。 

スレッドセーフ

3つのボールをジャグリングするたびに、空中のボールが、自然の異常によって、すでに右手に座っているボールが投げられるまで、右手に到達することが決して許されなかったと想像してみてください。少年、ジャグリングはずっと簡単でしょう!これがスレッドセーフのすべてです。私たちのプログラムでは、もう一方のスレッドがビジネスを終了している間、一方のスレッドをコードブロック内で待機させます。スレッドのブロックまたはスレッドの同期と呼ばれるこのアクティビティにより、プログラム内で実行される同時スレッドのタイミングを制御できます。C#では、メモリの特定の部分(通常はオブジェクトのインスタンス)をロックし、オブジェクトを使用して別のスレッドが完了するまで、スレッドがこのオブジェクトのメモリのコードを入力できないようにします。今ではおそらくコード例を渇望しているので、ここに行きます。

2スレッドのシナリオを見てみましょう。この例では、C#でスレッド1とスレッド2の2つのスレッドを作成します。どちらも、独自のwhileループで実行されます。スレッドは何の役にも立ちません。どのスレッドに属しているかを示すメッセージを出力するだけです。_threadOutputと呼ばれる共有メモリクラスメンバーを利用します。_threadOutputには、実行中のスレッドに基づいてメッセージが割り当てられます。リスト#1は、それぞれDisplayThread1とDisplayThread2に含まれる2つのスレッドを示しています。

リスト1-メモリ内で共通の変数を共有する2つのスレッドを作成する

// shared memory variable between the two threads  
// used to indicate which thread we are in  
private string _threadOutput = "";  
  
/// <summary>  
/// Thread 1: Loop continuously,  
/// Thread 1: Displays that we are in thread 1  
/// </summary>  
void DisplayThread1()  
{  
      while (_stopThreads == false)  
      {  
            Console.WriteLine("Display Thread 1");  
  
            // Assign the shared memory to a message about thread #1  
            _threadOutput = "Hello Thread1";  
  
  
            Thread.Sleep(1000);  // simulate a lot of processing   
  
            // tell the user what thread we are in thread #1, and display shared memory  
            Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);  
  
      }  
}  

/// <summary>  
/// Thread 2: Loop continuously,  
/// Thread 2: Displays that we are in thread 2  
/// </summary>  
void DisplayThread2()  
{  
      while (_stopThreads == false)  
      {  
        Console.WriteLine("Display Thread 2");  
  
  
       // Assign the shared memory to a message about thread #2  
        _threadOutput = "Hello Thread2";  
  
  
        Thread.Sleep(1000);  // simulate a lot of processing  
  
       // tell the user we are in thread #2  
        Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);  
  
      }  
}
Class1()  
{  
      // construct two threads for our demonstration;  
      Thread thread1 = new Thread(new ThreadStart(DisplayThread1));  
      Thread thread2 = new Thread(new ThreadStart(DisplayThread2));  
  
      // start them  
      thread1.Start();  
      thread2.Start();  
}

このコードの結果を図2に示します。結果を注意深く見てください。プログラムが驚くべき出力を提供することに気付くでしょう(これをシングルスレッドの考え方から見た場合)。_threadOutputを、それが属するスレッドに対応する番号の文字列に明確に割り当てましたが、コンソールでは次のように表示されます。

C#でのスレッド化

図2-2スレッドの例からの異常な出力。

私たちのコードから次のことが期待されます、

スレッド1の出力->ハロースレッド1とスレッド2の出力->ハロースレッド2ですが、ほとんどの場合、結果は完全に予測できません。 

スレッド2の出力->ハロースレッド1とスレッド1の出力->ハロースレッド2が表示されることがあります。スレッドの出力がコードと一致しません。コードを見て、それを目で追っていますが、_threadOutput = "Hello Thread 2"、Sleep、Write "Thread 2-> Hello Thread 2"ですが、このシーケンスで必ずしも最終結果が得られるとは限りません。 

説明

このようなマルチスレッドプログラムでは、理論的にはコードが2つのメソッドDisplayThread1とDisplayThread2を同時に実行しているためです。各メソッドは変数_threadOutputを共有します。したがって、_threadOutputにはスレッド#1で値 "Hello Thread1"が割り当てられ、2行後にコンソールに_threadOutputが表示されますが、スレッド#1がそれを割り当てて表示する時間の間のどこかで、スレッド#2が_threadOutputを割り当てる可能性があります。値「HelloThread2」。これらの奇妙な結果が発生する可能性があるだけでなく、図2に示す出力に見られるように、非常に頻繁に発生します。この痛みを伴うスレッドの問題は、競合状態として知られるスレッドプログラミングで非常に一般的なバグです。 この例は、よく知られているスレッドの問題の非常に単純な例です。この問題は、参照されている変数やスレッドセーフでない変数を指すコレクションなどを介して、プログラマーからはるかに間接的に隠されている可能性があります。図2では症状は露骨ですが、競合状態は非常にまれにしか現れず、1分に1回、1時間に1回、または3日後に断続的に現れる可能性があります。レースは、その頻度が低く、再現が非常に難しいため、おそらくプログラマーにとって最悪の悪夢です。

レースに勝つ

競合状態を回避する最善の方法は、スレッドセーフなコードを作成することです。コードがスレッドセーフである場合、いくつかの厄介なスレッドの問題が発生するのを防ぐことができます。スレッドセーフなコードを書くためのいくつかの防御策があります。1つは、メモリの共有をできるだけ少なくすることです。クラスのインスタンスを作成し、それが1つのスレッドで実行され、次に同じクラスの別のインスタンスを作成し、それが別のスレッドで実行される場合、静的変数が含まれていない限り、クラスはスレッドセーフです。 。2つのクラスはそれぞれ、独自のフィールド用に独自のメモリを作成するため、共有メモリはありません。クラスに静的変数がある場合、またはクラスのインスタンスが他の複数のスレッドによって共有されている場合は、他のクラスがその変数の使用を完了するまで、一方のスレッドがその変数のメモリを使用できないようにする方法を見つける必要があります。ロック。  C#を使用すると、Monitorクラスまたはlock {}構造のいずれかを使用してコードをロックできます。(lock構造は、実際にはtry-finallyブロックを介してMonitorクラスを内部的に実装しますが、プログラマーからこれらの詳細を隠します)。リスト1の例では、共有_threadOutput変数を設定した時点から、コンソールへの実際の出力まで、コードのセクションをロックできます。コードのクリティカルセクションを両方のスレッドでロックして、どちらか一方に競合が発生しないようにします。メソッド内をロックする最も速くて汚い方法は、このポインターをロックすることです。このポインタをロックすると、クラスインスタンス全体がロックされるため、ロック内でクラスのフィールドを変更しようとするスレッドはすべてブロックされます。。ブロッキングとは、変数を変更しようとしているスレッドが、ロックされたスレッドでロックが解除されるまで待機することを意味します。スレッドは、lock {}構造の最後のブラケットに到達すると、ロックから解放されます。

リスト2-2つのスレッドをロックして同期する

/// <summary>  
/// Thread 1, Displays that we are in thread 1 (locked)  
 /// </summary>  
 void DisplayThread1()  
 {  
       while (_stopThreads == false)  
       {  
          // lock on the current instance of the class for thread #1  
             lock (this)  
             {  
                   Console.WriteLine("Display Thread 1");  
                   _threadOutput = "Hello Thread1";  
                   Thread.Sleep(1000);  // simulate a lot of processing  
                   // tell the user what thread we are in thread #1  
                   Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);  
             }// lock released  for thread #1 here  
       }   
 }  

/// <summary>  
/// Thread 1, Displays that we are in thread 1 (locked)  
 /// </summary>  
 void DisplayThread2()  
 {  
       while (_stopThreads == false)  
       {  
  
           // lock on the current instance of the class for thread #2  
             lock (this)  
             {  
                   Console.WriteLine("Display Thread 2");  
                   _threadOutput = "Hello Thread2";  
                   Thread.Sleep(1000);  // simulate a lot of processing  
                   // tell the user what thread we are in thread #1  
                   Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);  
             } // lock released  for thread #2 here  
       }   
 }

2つのスレッドをロックした結果を図3に示します。すべてのスレッド出力が適切に同期されていることに注意してください。スレッド1の出力->ハロースレッド1とスレッド2の出力->ハロースレッド2という結果が常に表示されます。ただし、スレッドのロックにはコストがかかることに注意してください。スレッドをロックすると、ロックが解除されるまで他のスレッドを強制的に待機させます。本質的に、他のスレッドが共有メモリの使用を待機している間、最初のスレッドはプログラムで何もしていないため、プログラムの速度が低下しました。したがって、ロックは慎重に使用する必要があります。共有メモリに関与していない場合は、コード内にあるすべてのメソッドをロックするだけではいけません。また、ロックを使用するときは注意してください。スレッド#1がスレッド#2によってロックが解放されるのを待っている状況に陥りたくないからです。スレッド#2は、スレッド#1によってロックが解放されるのを待っています。この状況が発生すると、両方のスレッドがブロックされ、プログラムがフリーズしたように見えます。この状況はとして知られていますデッドロックが発生し、プログラム内の予測できない断続的な期間にも発生する可能性があるため、競合状態とほぼ同じくらい悪い状況です。 

  C#でのスレッド化

  図3-ロックを使用したデュアルスレッドプログラムの同期

代替ソリューション

.NETは、スレッドの制御に役立つ多くのメカニズムを提供します。別のスレッドが共有メモリの一部を処理している間、スレッドをブロックしたままにする別の方法は、AutoResetEventを使用することです。AutoResetEventクラスには、SetとWaitOneの2つのメソッドがあります。これらの2つの方法は、スレッドのブロックを制御するために一緒に使用できます。AutoResetEventがfalseで初期化されると、プログラムは、AutoResetEventでSetメソッドが呼び出されるまで、WaitOneを呼び出すコード行で停止します。AutoResetEventでSetメソッドが実行されると、スレッドのブロックが解除され、WaitOneを超えて続行できるようになります。次回WaitOneが呼び出されると、自動的にリセットされるため、プログラムは、WaitOneメソッドが実行されているコード行で再び待機(ブロック)します。この「停止とトリガー」を使用できます Setを呼び出して、別のスレッドがブロックされたスレッドを解放する準備ができるまで、あるスレッドをブロックするメカニズム。リスト3は、AutoResetEventを使用して、ブロックされたスレッドが待機し、ブロックされていないスレッドが実行されてコンソールに_threadOutputを表示している間に、互いにブロックする同じ2つのスレッドを示しています。最初に、_blockThread1はfalseを通知するように初期化され、_blockThread2はtrueを通知するように初期化されます。これは、_blockThread2がDisplayThread_2のループを最初に通過するときに、WaitOne呼び出しを続行できるようになる一方で、_blockThread1はDisplayThread_1のWaitOne呼び出しをブロックすることを意味します。_blockThread2がスレッド2のループの終わりに達すると、スレッド1をブロックから解放するためにSetを呼び出して_blockThread1に信号を送ります。次に、スレッド2は、スレッド1がループの終わりに到達して_blockThread2でSetを呼び出すまで、WaitOne呼び出しで待機します。スレッド1で呼び出されたセットはスレッド2のブロックを解放し、プロセスが再開されます。両方のAutoResetEvents(_blockThread1と_blockThread2)を最初にfalseを通知するように設定した場合、両方のスレッドが互いにトリガーする機会なしにループの進行を待機し、デッドロック。 

リスト3-あるいは、AutoResetEventでスレッドをブロックする

AutoResetEvent _blockThread1 = new AutoResetEvent(false);  
AutoResetEvent _blockThread2 = new AutoResetEvent(true);  
  
/// <summary>  
/// Thread 1, Displays that we are in thread 1  
/// </summary>  
void DisplayThread_1()  
{  
      while (_stopThreads == false)  
      {  
               // block thread 1  while the thread 2 is executing  
                _blockThread1.WaitOne();   
  
                // Set was called to free the block on thread 1, continue executing the code  
                  Console.WriteLine("Display Thread 1");  
  
                  _threadOutput = "Hello Thread 1";  
                  Thread.Sleep(1000);  // simulate a lot of processing  
  
                   // tell the user what thread we are in thread #1  
                  Console.WriteLine("Thread 1 Output --> {0}", _threadOutput);  
  
                // finished executing the code in thread 1, so unblock thread 2  
                  _blockThread2.Set();  
      }  
}  
  
/// <summary>  
/// Thread 2, Displays that we are in thread 2  
/// </summary>  
void DisplayThread_2()  
{  
      while (_stopThreads == false)  
      {  
            // block thread 2  while thread 1 is executing  
                  _blockThread2.WaitOne();   
  
            // Set was called to free the block on thread 2, continue executing the code  
                  Console.WriteLine("Display Thread 2");  
  
                  _threadOutput = "Hello Thread 2";  
                  Thread.Sleep(1000);  // simulate a lot of processing  
  
                   // tell the user we are in thread #2  
                  Console.WriteLine("Thread 2 Output --> {0}", _threadOutput);   
  
            // finished executing the code in thread 2, so unblock thread 1  
                _blockThread1.Set();  
      }  
} 

 

リスト3で生成される出力は、図3に示すロックコードと同じ出力ですが、AutoResetEventを使用すると、現在のスレッドが処理を完了したときに、あるスレッドが別のスレッドに通知する方法をより動的に制御できます。

結論

マイクロプロセッサの速度の理論的限界を押し上げているため、テクノロジは、コンピュータテクノロジの速度とパフォーマンスを最適化できる新しい方法を見つける必要があります。マルチプロセッサチップの発明と並列プログラミングへの侵入により、マルチスレッドを理解することで、ムーアの法則に挑戦し続けるために必要な利点をもたらすこれらのより最近のテクノロジーを処理するために必要なパラダイムに備えることができます。C#と.NETは、マルチスレッドと並列処理をサポートする機能を提供します。これらのツールを上手に活用する方法を理解すれば、私たち自身の日々のプログラミング活動において、将来のこれらのハードウェアの約束に備えることができます。一方、シャープなあなたができるので、スレッドのあなたの知識エン.NET可能性を。 

リンク:https://www.c-sharpcorner.com/article/introduction-to-multithreading-in-C-Sharp/

#csharp 

Elliott  Owen

Elliott Owen

1626882900

Flutter GetX Tutorial || Flutter GetX Unique ID #13

In this video I have discussed about unique id in getx

#flutter getx #getx #flutter #flutter getx tutorial